学习记录
// 尽管this.props和this.state是React本身设置的,且都拥有特殊的含义,但是其实你可以向class中随意添加不参与数据流(比如计时器Id)的额外字段
componentDidMount() {
this.timeId = setInterval(() => { // 这里把计时器Id(timeId)保存在this之中(this.timeId)
this.tick()
}, 1000)
}
// 我们会在componentWillUnmount()生命周期方法中清楚定时器:
componentWillUnmount() {
clearInterval(this.timeId)
}
正确使用State
// 1. 不要直接修改 State
/**
应该使用this.setState()
构造函数(constructor)是唯一可以给this.state赋值的地方
*/
// 2. State的更新可能是异步的
/**
因为this.props和this.state可能会异步更新,也就是暂时挂起,先执行后面的任务,所以不要依赖他们的值来更新下一个状态。
// 错误代码
this.setState({
counter: this.state.counter + this.props.increment
})
要解决这个问题,可以让setState()接收一个函数而不是一个对象,这个函数用上一个state作为第一个参数,将此次更新被应用时的props作为第二个参数
// 正确代码
this.setState((state, props) => ({ // 注意: 这里接收的函数返回的是一个对象, 否则报错
counter: state.counter + props.increment
}));
*/
// 3. State的更新会被合并
/**
即在this.setState({})接收的对象中,有写的属性就更新,没写的就不变
*/
数据是向下流动的
// (父组件)可以选择把它的state或者上一级传过来的props作为props向下传递到它的子组件中, 子组件会在其props中接收父组件传过来的参数,但是子组件无法知道它是来自于父组件的state,还是父组件的props,还是自己手动输入的。
常用的生命周期方法
生命周期图谱https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
![](https://img.haomeiwen.com/i11392927/d268865f76efc2ae.png)
render()
render()
方法是class组件中唯一必须实现的方法。
当render()
被调用时,他会检查this.props
和this.state
的变化并返回以下类型之一:
默认情况下,当组件的
state
或props
发生变化时,组件将重新渲染。如果render()方法依赖于其他数据,则可以调用forceUpdate()
强制让组件重新渲染。调用
forceUpdate()
将致使组件调用render()
方法,此操作会跳过该组件的shouldComponentUpdate()
。但其子组件会触发正常的生命周期方法。不过通常我们应该避免使用
forceUpdate()
,尽量在render()
中使用this.props
和this.state
- React元素。通常通过JSX创建。DOM节点 / 自定义组件
-
数组或者fragments。使得render方法可以返回多个元素,Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点
<React.Fragment>子列表分组</React.Fragment>
- Portals。可以渲染子节点到不同的DOM子树中。
- 字符串或数值类型。它们在DOM中会被渲染为文本节点
-
布尔类型或null。什么都不渲染。(主要用于支持返回
test && <Child />
的模式,其中test
为布尔类型)
render()
函数应该为纯函数,即在不修改组件state的情况下,每次调用都返回相同的结果,并且他不会直接与浏览器交互。如需与浏览器进行交互,请在componentDidMount
或其他生命周期中执行你的操作。
注意:
如果
shouldComponendtUpdate()
返回false,则不会调用render()
constructor():在组件挂载之前调用
constructor(props)
通常,在React中,constructor
构造函数仅用于以下两种情况:
- 通过给
this.state
来初始化内部state - 为事件处理函数绑定实例
this.handleClick = this.handleClick.bind(this)
注意:
在为React.Component子类实现构造函数时,应在其他语句之前调用
super(props)
,否则会出现this.props
未定义的bug要避免在
constructor
构造函数中引入任何副作用和订阅。应该把对应的操作放在componentDidMount
中
componentDidMount():在组件挂载后(插入DOM树中)立即调用
依赖于DOM节点的初始化应该放在这里。如请求获取数据,此处是实例化请求的好地方。也可以添加订阅,但是记住要在componentWillUnmount()
里取消订阅
componentDidUpdate():在组件更新后立即调用。
首次渲染不会执行此方法。可以对比更新前后的props,也可在此处进行网络请求。(如,当props未发生变化时,则不会执行网络请求)
注意:
如果
shouldComponentUpdate()
返回值为false,则不会调用componentDidUpdate()
componentWillUnmount():在组件卸载及销毁之前调用
在此方法执行必要的清理操作,例如,清除定时器,取消网络请求或清除订阅
事件处理
-
阻止默认行为
在React中不能通过返回false的方式来阻止默认行为(比如a标签的跳转),必须显式地使用
e.preventDefault()
-
绑定this
建议使用class field语法,不建议使用箭头函数,使用箭头函数会有性能问题
handleClick = () => { console.log('this is: ' + this) }
-
传递参数
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> // 箭头函数:事件对象e必须显式地进行传递 <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button> // bind: 事件对象e会被隐式地进行传递
状态提升
在React应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步state
组合 vs 继承
有点类似于vue
中的插槽。
React推荐使用组合而非继承来实现组件间的代码重用
父组件中在子元素标签之间直接写入一些元素,然后在子组件中通过{this.props.children}
来接收这些元素并渲染到结果中
// Child.js
function Child(props) {
return (
<div>
{props.children}
<div className="left">
{props.left}
</div>
</div>
)
}
// Father.js
function Father() {
return (
<Child left={<Custom />}>
<h1>title</h1>
<p>content</p>
</Child>
)
}
注意:
组合同样适合于class组件
组件可以接收任意的props,包括基本数据类型(比如要给dialog传一个"title"),React元素(上面代码的情况)以及函数(render props就是通过传递一个返回React元素的函数来实现的)
一般都不会用到继承,如果想要在组件间复用非UI的功能,建议将其提取为一个单独的javascript模块,如函数,对象或类。组件可以直接引入(import),而无需通过extend继承它们。
网友评论