若是你不初始化状态,也不绑定方法,那么你就不须要为React组件实现构造函数。在这里初始化状态能够直接对this.state赋值,在这里使用props时,应当经过this.props使用;若是组件内定义的方法不是采用箭头函数默认绑定到组件实例上时,调用时应该用bind手动绑定。java
在react17版本前有效的生命周期钩子,不能与新版钩子混用(componentWillRecevieProps、componentWillUpdate也是如此);
有一种常见的误区是在componentWillMount中请求数据能够避免第一次empty render,但实际中render在componentWillMount后当即执行,若是componentWillMount拉取的数据不能当即获得,那么二次渲染依然没法避免,这种状况下推荐在componentDidMount中请求数据。
因此总的来讲没啥用处。react
render()方法是类组件惟一必须的方法,在该钩子内,将React JSX 渲染为DOM节点。
render()函数应该是纯的,意味着不该该改变组件的状态,其每次调用都应返回相同的结果,同时它不会直接和浏览器交互segmentfault
在该钩子内,render生成的DOM节点挂载到DOM树中,在这里你能够经过ref取到DOM节点,有些需求下,可能须要DOM节点挂载后才能取到相应的属性,例如DOM节点的尺寸等,你能够当即调用setState()。它将会触发一次额外的渲染,可是它将在浏览器刷新屏幕以前发生。这保证了在此状况下即便render()将会调用两次,用户也不会看到中间状态。浏览器
componentWillUnmount()紧挨着在组件被卸载和销毁以前调用。能够在该方法里处理任何须要的清理工做,例如解绑定时器,取消网络请求,清理任何在componentDidMount环节建立的订阅。服务器
上述介绍的基本生命周期钩子是上图的左半部分,走完了一次初始渲染的流程,但React组件嵌套复用,当父组件更新或者组件自身状态更新触发子组件从新渲染时,合理的使用上图右半部分的生命周期钩子能够有效提高性能。网络
componentWillReceiveProps()在装载了的组件接收到新属性前调用。可能当接收到新属性后,经过if比较新旧Props不一样,想要经过this.setState()来更新组件的状态。数据结构
当接收到新属性或状态时,shouldComponentUpdate() 在渲染前被调用。默认为true。该方法在初始化渲染或当使用forceUpdate()时并不会被调用。
适用场景是:你想在某些状态或属性变化时,经过this.props和nextProps以及this.state 和 nextState比较,来判断是否须要从新渲染该组件,return fasle 不渲染,默认为true。不能setState。
有内建的React.PureComponent代替手写shouldComponentUpdate()。PureComponent 对属性和状态执行浅比较,于是下降你略过必要更新的机会。
但若是你须要更精细的控制,那就自定义shouldComponentUpdate吧。
可是当你的state或props是嵌套很深的引用类型时,容易因为浅比较而出错,而React文档说咱们不推荐作深相等检测,或使用JSON.stringify()在shouldComponentUpdate()中,这是很是无效率的会伤害性能。因此你最好设计好本身的数据结构,不要让数据嵌套太深。架构
相似于componentWillMount,在nextProps, nextState生效前最后的一次准备机会,能够读取DOM属性,为componentDidUpdate做准备(使用场景少)。不能setState。异步
组件更新后触发,相似于componentDidMount的做用,能够在这里操做DOM,发起请求等。函数
参考连接:
React Lifecycle Methods- how and when to use them
React组件生命周期小结
与旧的生命周期图比较能够看出,getDerivedStateFromProps处于原来的componentWillMount与componentWillReceiveProps位置,并且this.setState()以及this.forceUpdate()也会触发该钩子。
该钩子的主要做用是为了替代componentWillReceiveProps做用。
// Before class ExampleComponent extends React.Component { state = { isScrollingDown: false, }; componentWillReceiveProps(nextProps) { if (this.props.currentRow !== nextProps.currentRow) { this.setState({ isScrollingDown: nextProps.currentRow > this.props.currentRow, }); } } } // After class ExampleComponent extends React.Component { state = { isScrollingDown: false, lastRow: null, }; static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.currentRow !== prevState.lastRow) { return { isScrollingDown: nextProps.currentRow > prevState.lastRow, lastRow: nextProps.currentRow, }; } // Return null to indicate no change to state. return null; } }
与原有钩子相比,getDerivedStateFromProps是一个静态方法,没法访问组件实例,如此限制了其使用范围,防止不熟练的开发者自由发挥致使各类bug。该钩子主要做用能够归纳为接收props来改变state。
能够发如今使用getDerivedStateFromProps时,咱们在state中多花了一个变量lastRow来保存prevProps,为何设计钩子的时候不在参数值加入prevProps呢? 官方文档的解释是:1.首次渲染也会触发getDerivedStateFromProps,这意味着每次都须要对prevProps进行空置检测,麻烦;2.不将prevProps传入是为了节省内存。
取代componenWillUpdate功能。
getSnapshotBeforeUpdate在最新的渲染输出提交给DOM前将会当即调用。它让你的组件能在当前的值可能要改变前得到它们。这一辈子命周期返回的任何值将会 做为参数被传递给componentDidUpdate()。
class ScrollingList extends React.Component { listRef = null; getSnapshotBeforeUpdate(prevProps, prevState) { // Are we adding new items to the list? // Capture the current height of the list so we can adjust scroll later. if (prevProps.list.length < this.props.list.length) { return this.listRef.scrollHeight; } return null; } componentDidUpdate(prevProps, prevState, snapshot) { // If we have a snapshot value, we've just added new items. // Adjust scroll so these new items don't push the old ones out of view. // (snapshot here is the value returned from getSnapshotBeforeUpdate) if (snapshot !== null) { this.listRef.scrollTop += this.listRef.scrollHeight - snapshot; } } render() { return ( <div ref={this.setListRef}> {/* ...contents... */} </div> ); } setListRef = ref => { this.listRef = ref; }; }
错误处理。。。
render phase 里产生异常的时候, 会调用 getDerivedStateFromError;
在 commit phase 里产生异常大的时候, 会调用 componentDidCatch。
componentDidCatch 是不会在服务器端渲染的时候被调用的 而getDerivedStateFromError 会
主要是为了适应将要推出的异步渲染,其次是避免以前生命周期钩子的滥用。
React Fiber 是在 v16 的时候引入的一个全新架构, 旨在解决异步渲染问题,但v16并无开启。
同步渲染的痛点:当应用的组件树特别庞大时,因为javaScript是单线程的,从新渲染一旦开始,中间不会停,若是这时候用户去操做, 好比输入, 点击按钮, 此时页面是没有响应的。 等更新完了, 你以前的那些输入就会啪啪啪一会儿出来了。函数调用栈如图所示:
由于JavaScript单线程的特色,每一个同步任务不能耗时太长,否则就会让程序不会对其余输入做出相应,React的更新过程就是犯了这个禁忌,而React Fiber就是要改变现状。
Fiber 的作法是:分片。
把一个很耗时的任务分红不少小片,每个小片的运行时间很短,虽然总时间依然很长,可是在每一个小片执行完以后,都给其余任务一个执行的机会,这样惟一的线程就不会被独占,其余任务依然有运行的机会。 而维护每个分片的数据结构, 就是Fiber。
用一张图来展现Fiber 的碎片化更新过程
在React Fiber中,一次更新过程会分红多个分片完成,因此彻底有可能一个更新任务尚未完成,就被另外一个更高优先级的更新过程打断,这时候,优先级高的更新任务会优先处理完,而低优先级更新任务所作的工做则会彻底做废,而后等待机会重头再来。
由于一个更新过程可能被打断,因此React Fiber一个更新过程被分为两个阶段: render phase and commit phase.(能够从上文的生命周期图中看到)
由于第一阶段的过程会被打断并且“重头再来”,就会形成意想不到的状况。
好比说,一个低优先级的任务A正在执行,已经调用了某个组件的componentWillUpdate函数,接下来发现本身的时间分片已经用完了,因而冒出水面,看看有没有紧急任务,哎呀,真的有一个紧急任务B,接下来React Fiber就会去执行这个紧急任务B,任务A虽然进行了一半,可是没办法,只能彻底放弃,等到任务B全搞定以后,任务A重头来一遍,注意,是重头来一遍,不是从刚才中段的部分开始,也就是说,componentWillUpdate函数会被再调用一次。
在现有的React中,每一个生命周期函数在一个加载或者更新过程当中绝对只会被调用一次;在React Fiber中,再也不是这样了,第一阶段中的生命周期函数在一次加载和更新过程当中可能会被屡次调用!。
总而言之就是:
render phase 能够被打断, 你们不要在此阶段作一些有反作用的操做,能够放心在commit phase 里作。
而后就是生命周期的调整, react 把你有可能在render phase 里作的有反作用的函数都改为了static 函数, 强迫开发者作一些纯函数的操做。