组件刚加载的时候调用,在这里初始化state
组件每次被rerender
的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props
或state
之后;每次接收新的props之后都会返回一个对象作为新的state
,返回null
则说明不需要更新state
;配合componentDidUpdate
,可以覆盖componentWillReceiveProps
的所有用法
这个方法是静态的,无法通过this
获取到组件的属性
具体使用:
Class ColorPicker extends React.Component {
state = {
color: '#000000'
}
static getDerivedStateFromProps (props, state) {
if (props.color !== state.color) {
return {
color: props.color
}
}
return null
}
... // 选择颜色方法
render () {
.... // 显示颜色和选择颜色操作
}
}
state
,如果外部传进来一个state
跟本地不相同的话,就返回更新本地的state
null
不做任何处理但是如果这样的话会有一个问题,color
会只受props
的影响,内部触发的改变不会修改,因为在新版本的生命周期中,组件内部setState
也会触发这个生命周期,所以造成这样一个问题,下面来尝试解决:
Class ColorPicker extends React.Component {
state = {
color: '#000000',
prevPropColor: ''
}
static getDerivedStateFromProps (props, state) {
if (props.color !== state.prevPropColor) {
return {
color: props.color
prevPropColor: props.color
}
}
return null
}
... // 选择颜色方法
render () {
.... // 显示颜色和选择颜色操作
}
}
react
最重要的步骤,创建虚拟dom
,进行diff
算法,更新dom
树都在此进行
组件渲染之后调用,只会调用一次
内部的setState
或者forceUpdate
也会触发这个生命周期
组件接收到新的props
或者state
时调用,return true
就会更新dom
(使用diff算法更新),return false
能阻止更新(不调用render
)
shouldComponentUpdate(nextProps, nextState) {
return nextState.someData !== this.state.someData
}
state
与nextState
是否相同,不相同的话渲染,相同的话不render
但是这时候又面临一个问题,如果someData
是基本数据类型倒还好办,但是如果是引用数据类型的话,上面的判断恒为false
这时候为了解决这一问题:
– Object.assign()
– 深浅拷贝/JSON.parse(JSON.stringify(data))
– immutable.js
– PureComponent
更新数据,重新render
触发时间: update
发生的时候,在render
之后,在组件dom
渲染之前;返回一个值,作为componentDidUpdate
的第三个参数;配合componentDidUpdate
, 可以覆盖componentWillUpdate
的所有用法
使用场景:
1s钟往div
中插入一个<div>msg : number</div>
,这样话滚轮会动,如果保持滚轮不动呢?
class SnapshotSample extends React.Component {
constructor(props) {
super(props);
this.state = {
messages: [],//用于保存子div
}
}
handleMessage () {//用于增加msg
this.setState( pre => ({
messages: [`msg: ${ pre.messages.length }`, ...pre.messages],
}))
}
componentDidMount () {
for (let i = 0; i < 20; i++) this.handleMessage();//初始化20条
this.timeID = window.setInterval( () => {//设置定时器
if (this.state.messages.length > 200 ) {//大于200条,终止
window.clearInterval(this.timeID);
return ;
} else {
this.handleMessage();
}
}, 1000)
}
componentWillUnmount () {//清除定时器
window.clearInterval(this.timeID);
}
getSnapshotBeforeUpdate () {//很关键的,我们获取当前rootNode的scrollHeight,传到componentDidUpdate 的参数perScrollHeight
return this.rootNode.scrollHeight;
}
componentDidUpdate (perProps, perState, perScrollHeight) {
const curScrollTop= this.rootNode.scrollTop;
if (curScrollTop < 5) return ;
this.rootNode.scrollTop = curScrollTop + (this.rootNode.scrollHeight - perScrollHeight);
//加上增加的div高度,就相当于不动
}
render () {
return (
<div className = 'wrap' ref = { node => ( this.rootNode = node)} >
{ this.state.messages.map( msg => (
<div>{ msg } </div>
))}
</div>
);
}
这个生命周期的作用是当props
或state
更新之后,使用它更新DOM
节点。如果使用不当,则查询页面会不停的调用查询的方法,不停的执行刷新操作。因此,需要给新增的方法增加一个标志,通过这个标志,判断,如果新增成功,则调用一次查询方法,否则,则不调用
基本使用: 开发者在等界面完全render后进行一些请求或者其他操作,比如setState(),大多数情况下,为了避免循环调用这个函数,官方要求在函数内加一行判断,以确保不会陷入无限循环,例:
constructor(props){
super(props);
this.tmpData={};
// ... Other code
}
produce(data){
this.tmpData = arrayDeepCopy(data) // 假设生产出来的数据是{a: '123', b:{c: '234'}}
this.setState({data: data})
}
componentDidUpdate(prevProps, prevState){
if ( !arrayIdentical(this.tmpData, this.state.data) ){
// fetchUserData(userID)
}
}
组件销毁时调用,常用于关闭一些页面上的定时器
任意一处js报错都可以在这里捕获
getDerivedStateFromProps
、getSnapshotBeforeUpdate
来代替弃用的三个钩子函数(componentWillMount、componentWillReceivePorps,componentWillUpdate
)