React状态机和生命周期
状态机
React采用状态机的状态来重新渲染页面(不操作DOM),状态保存在实例变量state
中,该状态初始化后必须使用setState
来修改状态,否则不会触发重新渲染机制,初始化一般在构造中或者类中方法外
初始化:this.state={key:value,key,value}
修改状态:this.setState({key:value,key:value})
使用状态:this.state.key
// 这三种修改状态的写法都是可以的
handleClick() {
this.setState(state=>({
isToggleOn:!state.isToggleOn
})
)
}
handleClick2() {
this.setState(function(state) {
return {isToggleOn: !state.isToggleOn};
});
}
// 推荐这种写法
handleClick3() {
this.setState({
isToggleOn: !this.state.isToggleOn
});
}
构造函数使用constructor表示,且如需使用this,则必需调用super(props)
进行初始化
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date:new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('example')
);
注意:组件在调用过程中不关心是否是有状态的,数据从顶向下流动,某个组件的状态只能影响其下的子组件
生命周期
生命周期控制:可以在组件挂载和卸载时做一些事情,比如释放占用的资源。比如componentDidMount
这个是挂载时时,即组件输出到DOM时执行,componentWillUnmount
是卸载时处理
组件生命周期可分为三个状态:
Mounting(插入真实DOM)
Updating(正在渲染)
Unmounting(移出真实DOM)
生命周期方法(按照先后顺序)
-
初始
defaultProps
:静态属性,用于初始化props值
constructor
:如果之后的代码需要使用props,需要先调用super(props)方法,否则有可能有bug,这里面会执行state的赋值。注意:不要在构造函数中引入副作用或者订阅,在componentDidMount中使用。
static getDrivedStateFromProps
:静态方法,在render前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。此方法无权访问组件实例。
UNSAFE_componentWillMount()
在渲染前调用,该方法调用时表示组件对象的基础属性和方法都初始化完成。在该方法中调用this.setState不会引起组件重新渲染(因为组件此时还没有挂载到DOM上)【过时】
render
:页面触发渲染,在return前,无法通过getelement获取dom元素,render执行完,虚拟dom构建完毕才开始挂载页面。该方法之后就可以调用this.setState方法了。同时函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。
componentDidMount
: 在第一次渲染结束,DOM更新完毕后调用。常用来初始化页面数据,增加订阅或做异步请求获取数据。可以在 componentDidMount() 里直接调用 setState()。将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。需要谨慎使用该模式,因为它会导致性能问题。通常,应该在 constructor() 中初始化 state。如果渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,可以使用此方式处理 -
更新
static getDrivedStateFromProps
:静态方法,获取props参数,16.3时setState和forceUpdate时不会触发这个函数,16.4之后就会了。
UNSAFE_componentWillReceiveProps()(nextProps)
:方法,接收参数props为下一次的props值,里面this.props获取的为改变前的值。在这里改变state不会重渲染。
shouldComponentUpdate(nextProps,nextState)
:返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。可以传递两个值:其中this.state为旧状态值,而nextProps,nextStates为新状态值。返回 false 以告知 React 可以跳过更新。请注意,返回 false 并不会阻止子组件在 state 更改时重新渲染。不能在这里企图阻止渲染,只能作为性能优化方式。禁止在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。
UNSAFE_componentWillUpdate()(nextProps)
:在组件接收到新的props时,且仅在父组件重新渲染时触发与state状态无关。在初始化时不会被调用。
render
:页面触发渲染,执行完毕才会开始挂载到页面上去,即更新DOM和refs
static getSnapshotBeforeUpdate(preprops, prestate)
: 在最近一次更新渲染到Dom之前被调用(更新DOM前),可在此获得一些数值如滚动位置,该方法的返回值将作为componentDidUpdate()的第三个参数传入,如果没有调用该方法,则第三个参数为undefined
componentDidUpdate(prevProps, prevState,snapshot)
: 在组件完成DOM更新后立即调用。首次渲染不会执行此方法。注意,如果在这个方法中改变state请设立好条件,否则产生无限循环。 -
卸载
componentWillUnmount
:在组件从 DOM 中移除之前立刻被调用。用于做一些清理工作,比如取消订阅和清除定时器等。禁止在此方法中调用this.setState
/*
当页面发生跳转后但由于前一个页面请求还没有结束,或者事件 定时器没有结束,但是页面跳转到下一个页面了,此时就会报错。
通常是 react 组件已经从 DOM 中移除,但是我们在组件中做的一些异步操作还未结束,如:接口调用等,当其完成时,执行setState操作,而此时我们已经将改组件dom移除,从而导致上述问题。
作者:zyghhhh
链接:https://www.jianshu.com/p/ea3cfc0a85da
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/*
// 清除定时器
componentWillUnmount(){
clearTimeout(this.timer)
}
// 解绑dom事件
componentWillUnmount(){
//其他事件也类似
window.onScroll = null
}
// 清除react事件
componentWillUnmount(){
//其他事件也类似
this.setState = (state,callback) => {
return
}
}
- 错误处理
static getDerivedStateFromError(error)
:此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state,比如UI降级。会在渲染阶段调用,因此不允许出现副作用(回调方法)返回值会更新state相当于setState
componentDidCatch(error, info)
:会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况
参考图1:
参考图2:
官网生命周期图示:注意:getDerivedStateFromProps
在16.4前只有接收new props才更新!!
我总结的图示:
在绿色部分此时DOM已经更新完毕,如果再次改变状态会触发页面的重新渲染。深灰色的为过时方法,减少调用。
父子组件中的生命周期
在这种情况下:
- 组件初始化:render后开始构造子组件
父defaultProps
父constructor
父componentWillMount
父render
子defaultProps
子constructor
子componentWillMount
子render
子componentDidMount
父componentDidMount
- 组件更新,同初始化一样,在render后进入子组件更新
在父组件中改变某个state
父shouldComponentUpdate
父componentWillUpdate
父render
子componentWillReceiveProps
子shouldComponentUpdate
子componentWillUpdate
子render
子componentDidUpdate
父componentDidUpdate
- 卸载,由内向外
子componentWillUnmount
父componentWillUnmount
参考:https://developer.aliyun.com/article/780453