本篇内容主要是 React 的生命周期 (包括版本更新后的 API 变化), 先用原生 JS 的示例代码展示生命周期, 再展示 React 的生命周期,
在官网中 State and Lifecycle 可查看 API 的详情.
image.PNG
如图, React 生命周期主要包括三个阶段: 初始化阶段, 运行中阶段和销毁阶段, 在 React 不同的生命周期里, 会依次触发不同的钩子函数.
1. 原生 JS 里的生命周期
示例代码:
- let App = document.querySelector('#app')
- //create div
- let div = document.createElement('div')
- let state = 0
- //componentWillMount()
- //render
- div.innerhtml = `
- <p>${state}</p>
- <button>+1</button>
- <button>die</button>
- `
- //mount div
- App.appendChild(div)
- div.querySelector('button').onclick = ()=>{
- //update == render
- state += 1
- div.querySelector('p').innerText = state
- }
- //destory div
- div.querySelectorAll('button')[1].onclick = ()=>{
- div.querySelector('button').onclick = null
- div.querySelectorAll('button')[1].onclick = null
- div.remove()
- div = null
- }
上面例子中的 div 有 4 个动作: 生成, 挂载, 更新, 死亡.
2. React 里的生命周期
函数是没有生命周期的, 需用到 class
- class App extends React.Component {
- constructor() {
- super();
- // 1. 加载默认状态
- this.state = {
- amount: 100,
- };
- console.log('1.constructor: 创建 App')
- }
- componentWillMount() {
- console.log('2. App 组件将要挂载');
- }
- add() {
- console.log("点击了 App 的 +1 按钮")
- this.setState({
- amount: this.state.amount + 1
- });
- }
- render() {
- console.log('3. render:App 组件挂载渲染')
- return(
- <div className="App">
- <div>{this.props.n}</div>
- <span>amount: {this.state.amount}</span>
- <button onClick={() => this.add()}>+1</button>
- </div>
- );
- }
- componentDidMount() {
- console.log('4. App 组件挂载之后')
- }
- // 到此, App 组件的「初始化阶段」结束, 进入「进行时阶段」
- //5. 这一步可以做性能优化点, 判断是否真的要更新.
- shouldComponentUpdate(nextPros, nextState) {
- console.log('5. 判断是否要更新')
- if (this.state.n === nextState.n) {
- return true;
- } else {
- return false;
- }
- }
- componentWillUpdate() {
- console.log('6. App 组件将要更新啦!');
- }
- // 7. 重新 render
- componentDidUpdate() {
- console.log('8. App 组件更新完毕!')
- }
- // 9. 如果我们先操作 UnMount
- componentWillUnmount() {
- // 在「Parent」组件中点击「go die」按钮, 会销毁「App 组件」
- console.log('9. App 组件即将销毁');
- }
- // 10. 当 App 组件从 Parent 组件收到的 Props 改变, 执行.
- componentWillReceiveProps() {
- console.log('10. App 组件接受的 Props 改变了')
- }
- // 11. 再次进入 第 5 步的「componentWillUpdate」
- }
- class Parent extends React.Component {
- constructor() {
- super();
- this.state = {
- hasChild: true,
- n: 0
- }
- console.log('创建 Parent')
- }
- add() {
- console.log('点击了 Parent 的 + 1 按钮')
- this.setState({
- n: this.state.n + 1
- });
- }
- removeChild() {
- // 消灭 App 组件
- this.setState({
- hasChild: false
- });
- }
- render() {
- return(
- <div className="parent">
- <span>n: {this.state.n}</span>
- <button onClick={() => this.add()}>+1</button>
- <button onClick = {() => this.removeChild()}>go die</button>
- {
- this.state.hasChild ? <App n={this.state.n}/> : null
- }
- </div>
- );
- }
- }
- const rootElement = document.getElementById("root");
- ReactDOM.render(<Parent />, rootElement);
代码在线地址
3. 版本更新了
在即将到来的 React17.0 版本, React 团队对生命周期做了调整, 将会移除 componentWillMount,componentWillReceiveProps,componentWillUpdate 这三个生命周期, 因为这些生命周期方法容易被误解和滥用.
3.1 过时的生命周期函数
这些函数仍然有效, 但不建议在新代码中使用它们.
componentWillMount,componentWillReceiveProps,componentWillUpdate 这三个生命周期, 更改名称为:
- UNSAFE_componentWillMount()
- UNSAFE_componentWillReceiveProps()
- UNSAFE_componentWillUpdate
中文文档地址
3.2 新增的生命周期函数
getDerivedStateFromProps
当组件实例化的时候, 这个方法替代了
componentWillMount()
, 而当接收到新的 props 时, 该方法替代了
componentWillReceiveProps()
和
componentWillUpdate()
触发时机: 会在每次组件被重新渲染前被调用, 这意味着无论是父组件的更新, props 的变化, 或是组件内部执行了 setState(), 它都会被调用.
注意: componentWillReceiveProps 和 getDerivedStateFromProps 同时存在, 控制台会报错.
getDerivedStateFromProps 会在调用 render 方法之前调用, 并且在初始挂载及后续更新时都会被调用.
getSnapshotBeforeUpdate
这函数会在 render 之后执行, 而执行之时 DOM 元素还没有被更新, 给了一个机会去获取 DOM 信息, 计算得到一个 snapshot, 这个 snapshot 会作为 componentDidUpdate 的第三个参数传入.
这个函数应该大部分开发者都用不上 (潜台词就是: 不要用!)
3.3 自动更名
- If you don't have the time to migrate or test these components, we recommend running a"codemod" script that renames them automatically:
- cd your_project
- npx react-codemod rename-unsafe-lifecycles
4. 总结
挂载
当组件实例被创建并插入 DOM 中时, 其生命周期调用顺序如下:
- constructor()
- static getDerivedStateFromProps()
- render()
- componentDidMount()
更新
当组件的 props 或 state 发生变化时会触发更新. 组件更新的生命周期调用顺序如下:
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
用一个静态函数 getDerivedStateFromProps 来取代被 deprecate 的几个生命周期函数, 就是强制开发者在 render 之前只做无副作用的操作, 而且能做的操作局限在根据 props 和 state 决定新的 state, 而已.
卸载
当组件从 DOM 中移除时会调用如下方法:
componentWillUnmount()
来个图吧
image.PNG
来源: http://www.jianshu.com/p/826efa229c54