推荐入门学习链接:http://www.ruanyifeng.com/blog/2015/03/react.html
hooks学习链接:http://www.ruanyifeng.com/blog/2019/09/react-hooks.html

1.jsx条件知识点
- 变量、表达式
- class style
- 子元素和组件
经常用就不仔细分析了
2.事件
- bind this
- 关于event参数
- 传递自定义参数
1.为什么需要bind this?
我们先来看一段代码
import React, { Component } from "react";class JsxBaseDemo extends Component {constructor(props) {super(props);this.state = {name: "小明",};}handleClick(){console.log('this....',this)this.setState({name:'大明'})}render() {return (<div><span onClick={this.handleClick}>{this.state.name}</span></div>);}}export default JsxBaseDemo;

可以看出this的值为undefined。
解决办法有两种,第一种采用bind this的方式将this绑定在实例上。
第二种采用静态方法使this指向实例。
2.关于event参数
先来看一段代码
import React, { Component } from "react";class JsxBaseDemo extends Component {// 静态方法this指向实例handleClick = (event) =>{event.preventDefault() // 阻止默认行为console.log('target',event.target) //触发 指向当前元素console.log('currentTarget',event.currentTarget) // 绑定 指向当前元素,假象!!console.log('event',event)console.log('nativeEvent',event.nativeEvent) // 原生事件对象console.log('target',event.nativeEvent.target) // 触发console.log('currentTarget',event.nativeEvent.currentTarget) // 绑定}render() {return (<div><a onClick={this.handleClick} href="http://www.baidu.com">跳转</a></div>);}}export default JsxBaseDemo;
event.preventDefault() 阻止默认行为,使得a标签失去原有的能力。
console.log(‘currentTarget’,event.currentTarget)指向当前元素是假象!!
如何理解呢?我们来看看event事件的原型。 event.proto.constructor 。下图可以清晰的看到console.log(‘event’,event)的原型是一个组合事件,并不是原生MouseEvent的事件。
真正的原生event事件 是console.log(‘nativeEvent’,event.nativeEvent)。
总结一下:
- react的event实际上是SyntheticEvent(是一个组合事件并不是原生事件)模拟出dom事件的所有能力
- event.nativeEvent是原生事件对象
- 所有的事件都被挂载到document上
-
3.传参
handleClick = (id, event) => {event.preventDefault();console.log(id);console.log(event);};render() {return (<div><a onClick={(event) => this.handleClick(1,event)} href="http://www.baidu.com"> //默认追加一个event参数跳转</a></div>);}
3.表单
受控组件
-
1.受控组件
受state的控制 ```javascript class JsxBaseDemo extends Component { constructor(props) { super(props); this.state = {
name: "lin",
}; }
handleChange = (e) => { this.setState({
name: e.target.value,
}); };
render() { return (
<div><p>{this.state.name}</p><label htmlFor="inputName">姓名:</label><input type="text" id="inputName" onChange={this.handleChange} /></div>
); } }
export default JsxBaseDemo;
<a name="60Pt4"></a>##### 2.非受控组件非受控组件在高阶组件中讲解<a name="mJiMG"></a>### 4.组件使用- props传递数据- props类型检查- props传递函数```javascriptimport React from 'react'import PropTypes from 'prop-types'class Input extends React.Component {constructor(props) {super(props)this.state = {title: ''}}render() {return <div><input value={this.state.title} onChange={this.onTitleChange}/><button onClick={this.onSubmit}>提交</button></div>}onTitleChange = (e) => {this.setState({title: e.target.value})}onSubmit = () => {const { submitTitle } = this.propssubmitTitle(this.state.title) // 'abc'this.setState({title: ''})}}// props 类型检查Input.propTypes = {submitTitle: PropTypes.func.isRequired}class List extends React.Component {constructor(props) {super(props)}render() {const { list } = this.propsreturn <ul>{list.map((item, index) => {return <li key={item.id}><span>{item.title}</span></li>})}</ul>}}// props 类型检查List.propTypes = {list: PropTypes.arrayOf(PropTypes.object).isRequired}class Footer extends React.Component {constructor(props) {super(props)}render() {return <p>{this.props.text}{this.props.length}</p>}componentDidUpdate() {console.log('footer did update')}shouldComponentUpdate(nextProps, nextState) {if (nextProps.text !== this.props.text|| nextProps.length !== this.props.length) {return true // 可以渲染}return false // 不重复渲染}// React 默认:父组件有更新,子组件则无条件也更新!!!// 性能优化对于 React 更加重要!// SCU 一定要每次都用吗?—— 需要的时候才优化}class TodoListDemo extends React.Component {constructor(props) {super(props)// 状态(数据)提升this.state = {list: [{id: 'id-1',title: '标题1'},{id: 'id-2',title: '标题2'},{id: 'id-3',title: '标题3'}],footerInfo: '底部文字'}}render() {return<div><Input submitTitle={this.onSubmitTitle}/><List list={this.state.list}/><Footer text={this.state.footerInfo} length={this.state.list.length}/></div>}onSubmitTitle = (title) => {this.setState({list: this.state.list.concat({id: `id-${Date.now()}`,title})})}}export default TodoListDemo
5.setState
- 不可变值
- 可能是异步更新
-
1.不可变值
```javascript class StateDemo extends React.Component { constructor(props) {
super(props)// 第一,state 要在构造函数中定义this.state = {count: 0}
} render() {
return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>
} increase = () => {
// 第二,不要直接修改 state ,使用不可变值 ----------------------------// this.state.count++ // 错误// this.setState({// count: this.state.count + 1 // 正确SCU// })// 操作数组、对象的的常用形式// -------------------------- 我是分割线 -----------------------------// 注意做setState修改值时// 不可变值(函数式编程,纯函数) - 数组 不要修改原数组// const list5Copy = this.state.list5.slice() // 类似深拷贝 不会影响原来的值// list5Copy.splice(2, 0, 'a') // 中间插入/删除// this.setState({// list1: this.state.list1.concat(100), // 追加// list2: [...this.state.list2, 100], // 追加// list3: this.state.list3.slice(0, 3), // 截取// list4: this.state.list4.filter(item => item > 100), // 筛选// list5: list5Copy // 其他操作// })// 注意,不能直接对 this.state.list 进行 push pop splice 等,这样违反不可变值// 不可变值 - 对象// this.setState({// obj1: Object.assign({}, this.state.obj1, {a: 100}),// obj2: {...this.state.obj2, a: 100}// })// 注意,不能直接对 this.state.obj 进行属性设置,这样违反不可变值}
export default StateDemo
总结一下:不可变值就是需要在setState中设置state操作,不要提前做修改。如果提前修改要对原来的state值做下深拷贝,保证不影响原state中的值。虽然使用不规范不会造成错误,但是会影响性能和渲染。<a name="WjJdN"></a>##### 2.可能是异步更新**1.场景一:直接用:异步**```javascriptimport React, { Component } from "react";class JsxBaseDemo extends Component {constructor(props) {super(props);this.state = {count: 0,};}handleClick = (e) => {this.setState({count: this.state.count + 1,},() => {// 相当于vue中nextTickconsole.log('callback count',this.state.count) // 回调函数中可以拿到最新的 state});console.log('count',this.state.count) //异步的 拿不到最新的值};render() {return (<div><p>{this.state.count}</p><button onClick={this.handleClick}>追加</button></div>);}}export default JsxBaseDemo;
结论:直接用,setState是异步的,拿不到最新的值,可以在回调函数中拿到最新的值
2.场景二:setTimeOut:同步
import React, { Component } from "react";class JsxBaseDemo extends Component {constructor(props) {super(props);this.state = {count: 0,};}handleClick = (e) => {setTimeout(() => {this.setState({count: this.state.count + 1, // setTimeout中是同步的});console.log('count in setTimeout',this.state.count)},0)};render() {return (<div><p>{this.state.count}</p><button onClick={this.handleClick}>追加</button></div>);}}export default JsxBaseDemo;
结论:setTimeout 中 setState 是同步的
3.场景三:自定义事件:同步
import React, { Component } from "react";class JsxBaseDemo extends Component {constructor(props) {super(props);this.state = {count: 0,};}componentDidMount() {// 自己定义的 DOM 事件,setState 是同步的document.body.addEventListener("click", this.bodyClickHandler);}bodyClickHandler = () => {this.setState({count: this.state.count + 1,});console.log("count in body event", this.state.count);};componentWillMount() {// 及时销毁自定义 DOM事件document.body.removeEventListener("click", this.bodyClickHandler);}render() {return (<div><p>{this.state.count}</p><button onClick={this.handleClick}>追加</button></div>);}}export default JsxBaseDemo;
3.可能被合并
1.传入对象会被合并
import React, { Component } from "react";class JsxBaseDemo extends Component {constructor(props) {super(props);this.state = {count: 0,};}handleClick = () => {// 传入对象,会被合并(类似 Object.assign )。执行结果只一次 +1this.setState({count: this.state.count + 1,});this.setState({count: this.state.count + 1,});this.setState({count: this.state.count + 1,});};render() {return (<div><p>{this.state.count}</p><button onClick={this.handleClick}>追加</button></div>);}}export default JsxBaseDemo;
2.传入函数不会被合并
import React, { Component } from "react";class JsxBaseDemo extends Component {constructor(props) {super(props);this.state = {count: 0,};}handleClick = () => {// 传入函数,不会被合并。执行结果是 +3this.setState((prevState, props) => {return {count: prevState.count + 1,};});this.setState((prevState, props) => {return {count: prevState.count + 1,};});this.setState((prevState, props) => {return {count: prevState.count + 1,};});};render() {return (<div><p>{this.state.count}</p><button onClick={this.handleClick}>追加</button></div>);}}export default JsxBaseDemo;
6.组件生命周期
1.constructor
- 用于初始化内部状态,很少使用
-
2.getDervedStateFromProps
当state需要从props初始化时使用
- 尽量不要使用:维护两者状态一致性会增加复杂度
- 每次render都会调用
- 典型场景:表单控件获取默认值
3.componentDidMount
- UI渲染完成后调用
- 只执行一次
- 典型场景:获取外部资源
4.componentWillUnMount
- 组件移除时会被调用
- 典型场景:资源释放
5.getSnapshotBeforeUpdate
- 在页面render之前被调用,state已更新
- 典型场景:获取render之前的DOM状态
6.componentDidUpdate
- 每次UI更新时会调用
- 典型场景:页面需要根据props变化重新获取数据
7.shouldComponentUpdate
- 决定Virtual Dom是否重绘
- 一般可以由PureComponent自动实现
- 典型场景:性能优化
