说明
React 组件的生命周期笔记整理。
官方文档
生命周期函数:指在某一个时刻组件会自动调用执行的函数。
React v16.0前的生命周期
红框中的是react 16.0 之后已废弃的。
我们的react 版本是:15.5.4。
React v16.3 的生命周期
React v16.4 及之后的生命周期图
组件的生命周期【必会】
1. 挂载
当组件实例被创建并插入 DOM 中时
- constructor() ——设置state、props
- render()
- react更新DOM
- componentDidMount()
2. 更新
当组件的 props
或 state
(通过setState()
) 发生变化时会触发更新
- render()
- react更新DOM
- componentDidUpdate()
props
的改变,其实也是因为父组件的state
的改变
3. 卸载
当组件从 DOM 中移除时
- componentWillUnmount()
注意:render()
函数必须自己定义!
生命周期图(常用的)
生命周期图(全)
get derived state from props
:从prop获取派生的状态(此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props)[dɪ'raɪvd]
get snapshot before update
: 更新前获取快照['snæpʃɒt]
官方生命周期图
介绍
1. constructor()
如果不初始化 state
或不进行方法绑定,则不需要为 React 组件实现构造函数。
在 React 中,构造函数仅用于以下两种情况:
- 给
this.state
赋值:通过给this.state
赋值对象来初始化内部state
。 - 为事件处理函数绑定实例
注意
- 只能在构造函数中直接为
this.state
赋值!且不要在constructor()
函数中调用this.setState()
。 - 更新state则应使用
this.setState()
。 - 要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在
componentDidMount
中。 - 避免将
props
的值复制给state
!这是一个常见的错误!
2. render()
render() 函数应该为纯函数!
如需与浏览器进行交互,请在 componentDidMount()
或其他生命周期方法中执行你的操作。保持 render()
为纯函数,可以使组件更容易思考。
有副作用的操作,如 API 请求和路由跳转;
非纯函数,如Date.now() 或 Math.random()
纯函数:给定固定的输入,就一定会有固定的输出,而且不会有任何副作用。(一旦函数内有异步操作(setTimeout
、setInterval
、ajax
请求 等)、new Date()
、 Math.random()
、内部对函数的参数做修改 等时,就不是纯函数了)
redux中的reducer()函数也是纯函数
【注意】
- 当组件的
state
、props
发生改变时,会重新执行render()
函数; - 当父组件的
render()
函数执行时,它的子组件的render()
函数也都将被重新执行一次。(不论是否有传数据给字组件。)
3. componentDidMount()
在组件挂载后(插入 DOM 树中)会立即调用componentDidMount()
。
- 依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。【重点】
- 这个方法是比较适合添加订阅的地方(如果添加了订阅,请不要忘记在
componentWillUnmount()
里取消订阅)【不太理解???】
你可以在 componentDidMount() 里可以直接调用 setState()(注意是直接调用,而不是在异步函数如setTimeout、ajax调用哈)。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。
4. componentDidUpdate()
在更新后会立即调用componentDidUpdate()
。首次渲染不会执行此方法。
componentDidUpdate(prevProps, prevState, snapshot)
5. componentWillUnmount()
在组件卸载及销毁之前会直接调用componentWillUnmount()
。
在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。 ,但不应再调用 setState()
了(毫无意义了)。
shouldComponentUpdate(nextProps, nextState)—— 可减少重复渲染
推荐文章《react如何通过shouldComponentUpdate来减少重复渲染》
函数内必须return true
或者return false
;
为什么需要使用shouldComponentUpdate?
在react开发中,经常会遇到组件重复渲染的问题:父组件一个state的变化(则父组件会重新执行一次render函数),就会导致该组件的所有子组件都重新执行各自的render,尽管绝大多数子组件的props没有变化。
React会根据 shouldComponentUpdate()
的返回值,判断 React 组件的输出是否受当前 state
或 props
更改的影响。
当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true,则当 props 或 state 发生变化时,会生成新的虚拟DOM,对比新老虚拟DOM,更新真实的DOM。首次渲染或使用 forceUpdate() 时不会调用该方法。
优点
可提高组件的性能,因为可以避免组件render()
函数的无谓运行(会引起生成新的虚拟DOM、新老虚拟DOM的比对、真实DOM的渲染)。
但是,state里的数据这么多,还有对象,还有复杂类型数据,react的理念就是拆分拆分再拆分,这么多子组件,我要每个组件都去自己一个一个对比吗?不存在的,这么麻烦,要知道我们的终极目标是不劳而获:可以使用React.PureComponent
(但这个只是做了浅比较,复杂的话还可以考虑pureComponent 配合使用插件immutable-js
)。
具体查看我的文章里的这部分内容:React.PureComponent+immutable.js
我们公司的组件大部分都是使用React.pureComponent
的哟,也使用了immutable
。
React.Component
和React.PureComponent
的区别?
都可以被继承来创建react组件。
React.PureComponent
:内部以浅层对比prop
和state
的方式实现了shouldComponentUpdate()
函数。(注意:因为是浅比较,所以仅适合在你的 props 和 state 较为简单时使用。适合纯展示组件。(PureComponent含义为纯洁的组件——我的理解)React.Component
:未实现,所以需要我们自己调用shouldComponentUpdate()
生命周期函数进行操作。
推荐文章《React之PureComponent》
官方文档
浅比较:会比较 Object.keys(state | props) 的长度是否一致,每一个 key 是否两者都有,并且是否是一个引用,也就是只比较了第一层的值,确实很浅,所以深层的嵌套数据是对比不出来的。
比如:
this.state = {a:1,b:{name:'caicai'}};
var copy = Object.assign({},this.state);// 浅复制
copy.b.name = 'shitou';
copy.b.age = 22;
state.a === copy.a // true 基本数据类型是值比较
state.b === copy.b // true 浅比较,因为引用相同
// 搜索组件:用户在【输入框+'筛选'按钮】组件中输入内容时不更新选项列表组件,只有当点击'筛选'按钮时才更新
class ProductItem extends Component {
shouldComponentUpdate(nextProps, nextState) {
// 只有当点击'筛选'按钮等使this.props.list发生改变时才会update此组件(input时不会)
// 此时nextProps是最新的props数据,this.props.list是上一次的数据。但是render()里的this.props.list也是最新的。
if (nextProps.list === this.props.list) {
return false; // 不更新
} else {
return true; // 更新
}
}
render() {...}
}
我的快速小结react生命周期
1.创建时:
constructor()
getDerivedStateFromProps()
render()——> 生成虚拟DOM ——> 生成真实DOM ——>
react更新DOM
componentDidMount
2.更新时:
props、state改变(setState()),forceUpdate()
getDerivedStateFromProps() [dɪ'raɪvd]
shouldComponentUpdate ——> true ——>
render()——> 生成虚拟DOM ——>对比此次的虚拟DOM和上一次的虚拟DOM——> 找到区别 ——>
react更新真实DOM
componentDidUpadate
3.卸载时
componentWillUnmount