我正在参加「掘金·启航计划」
一、React生命周期(初始化)
1.1 初始化阶段
1、
componentWillMount:render之前最后一次修改状态的机会 (注意:将被弃用,不被推荐使用。如果有需求,官方推荐在constructor中去做或者改成UNSAFE_componentWillMount)(为什么被弃用?在react16.2之后发生了改变,推出了新的生命周期,旧的生命周期将被启用,) 2、render:只能访问this.props和this.state,不允许修改状态和DOM输出 3、componentDidMount:成功render并渲染完成真实DOM之后触发,可以修改DOM(初始化,执行一次)
1.2 示例
新建Lifecycle.js组件,写入如下代码:
import React, { Component } from 'react'
export default class Lifecycle extends Component {
state = {
text: 'react'
}
componentWillMount() {
console.log("will mount", this.state.text, document.getElementById('text'))
// 第一次上树前的 最后一次修改状态
this.setState({
text: "React"
})
}
componentDidMount() {
console.log("did mount", document.getElementById('text'))
// 数据axios数据请求
// 订阅函数调用
// setInterval
// 基于创建完的dom进行初始化
}
render() {
console.log('render')
return (
<div >
<span id="text">{this.state.text} Life cycle</span></div>
)
}
}
可以看到效果:
二、React生命周期(运行中)
2.1 运行中阶段
1、
componentWillReceiveProps:父组件修改属性触发 2、shouldComponentUpdate:返回false会阻止render调用(每次改变setState都会执行componentWillUpdate,render,componentDidUpdate。利用shouldComponentUpdate判断state的值是否改变,没有改变的话就return false;) 3、componentWillUpdate:不能修改属性和状态(注意:将被弃用,不被推荐使用。如果有需求,或者改成UNSAFE_componentWillUpdate)(为什么被弃用?在react16.2之后发生了改变,推出了新的生命周期,旧的生命周期将被启用,) 4、render:只能访问this.props和this.state,不允许修改状态和DOM输出 5、componentDidUpdate:可以修改DOM(在componentDidUpdate有两个参数,prevProps,preState,可以在componentDidUpdate判断prevProps)
2.2 示例
新建service.js组件,写入:
import React, { Component } from 'react'
export default class Service extends Component {
state = {
name: 'react'
}
render() {
console.log('render')
return (
<div>
<button onClick={() => {
this.setState({
name: 'React'
})
}}>click</button>
{this.state.name}
</div>
)
}
shouldComponentUpdate(nextProps,nextState) {
// nextProps 老状态
// nextState 新状态
if (JSON.stringify(this.state) !== JSON.stringify(nextState)) {
return true;
}
return false;
}
componentWillUpdate() {
console.log("componentWillUpdate")
}
componentDidUpdate() {
console.log("componentDidUpdate")
// 更新后,要获取dom节点
}
}
效果:
2.3 shouldComponentUpdate性能优化示例
新建scu.js组件,写入代码:
import React, { Component } from 'react'
class Child extends Component {
// 现在是全部子组件都会diff算法
// 在scu生命组件中 优化 比对即将更改的子组件
shouldComponentUpdate(nextProps) {
if (this.props.index === this.props.active || nextProps.index === nextProps.active) {
console.log(this.props.index, this.props.active, nextProps.index, nextProps.active)
return true
}
return false
}
render() {
console.log('Child render')
return (
<div style={{
width: '200px',
height: '200px',
border: '3px solid',
float: 'left', marginLeft: '20px', marginBottom: '20px',
borderColor: this.props.index === this.props.active ? 'red' : 'gray'}}>
</div>
)
}
}
export default class Scu extends Component {
state = {
list: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
active: '0'
}
render() {
return (
<div>
<input style={{ marginBottom: '20px' }} onChange={(event) => {
this.setState({
active: event.target.value
})
}}></input>
<div style={{ overflow: 'hidden' }}>
{this.state.list.map((item, index) => {
return <Child index={String(index)} active={this.state.active} key={index}>{item}</Child>
})}
</div>
</div>
)
}
}
效果:
可以看到只更新两次。
2.4 componentWillReceiveProps示例
创建ReceiveProps.js组件写入代码:
import React, { Component } from 'react'
class Child extends Component {
componentWillReceiveProps() {
console.log('componentWillReceiveProps')
}
render() {
return (
<div>
Child
</div>
)
}
}
export default class ReceiveProps extends Component {
state = {
text: 'react'
}
render() {
return (
<div>
{
this.state.text
}
<button onClick={() => {
this.setState({
text: 'React'
})
}}>
click
</button>
<Child></Child>
</div>
)
}
}
效果:
可以看到父组件更新,子组件的生命周期
componentWillReceiveProps也被触发了,所以这样子是会影响性能。
三、React生命周期(销毁)
3.1 销毁阶段
componentWillUnmount:在删除组件之前进行清理操作,比如计时器和事件监听器解绑。
3.2 示例
新建componentWillUnmount.js组件,写入代码:
import React, { Component } from 'react'
export default class ComponentWillUnmount extends Component {
state = {
flag: true
}
render() {
return (
<div>
<button onClick={() => {
this.setState({
flag: !this.state.flag
})
}}>click</button>
{this.state.flag && <Child></Child>}
</div>
)
}
}
class Child extends Component {
componentDidMount() {
this.timer = setInterval(() => {
console.log(888)
}, 1000)
}
render () {
return (
<div>子组件</div>
)
}
componentWillUnmount() {
clearInterval(this.timer)
}
}
效果:
可以看到子组件存在时计时器一直在运行,当我们将子组件销毁时,我们需求将此计时器清空,可以看到我们在销毁组件钩子函数中,进行了该操作。
四、React新生命周期
4.1 老生命周期问题
1、
componentWillMount,在ssr中这个方法将会被多次调用,所以会重复触发多遍,同时在这里如果绑定事件,将无法解绑,导致内存泄露,变得不够安全高效逐步废弃。 2、componentWillReceiveProps外部组件多次频繁更新传入多次不同的props,会导致不必要的异步请求 3、componentWillUpdate,更新前记录DOM状态,可能会做一些处理,与componentDidUpdate相隔时间如果过长,会导致状态不太行
4.2 getDerivedStateFromProps
getDerivedStateFromProps第一次的初始化组件以及后续的更新过程中(包括自身状态更新以及父传子),返回null则说明不需要在这里更新state。(取代componentWillMount,componentWillReceiveProps)
新建getDerivedStateFromProps.js组件,写入代码:
import React, { Component } from 'react'
export default class GetDerivedStateFromProps extends Component {
state = {
name: 'react'
}
// 初始化执行 状态改变也会执行
static getDerivedStateFromProps(nextProps, nextState) {
console.log('GetDerivedStateFromProps')
return {
name: nextState.name.substring(0,1).toUpperCase() +
nextState.name.substring(1)
}
}
render() {
return (
<div>
<button onClick={() => {
this.setState({
name: 'hello react GetDerivedStateFromProps'
})
}}>click</button>
<div>{this.state.name}</div>
</div>
)
}
}
效果:
4.3 getSnapshotBeforeUpdate
getSnapshotBeforeUpdate取代了componentWillUpdate,触发时间为update发生的时候,在render之后dom渲染之前返回一个值,作为componentDidUpdate的第三个参数。
新建getSnapshotBeforeUpdate.js组件,写入代码:
import React, { Component } from 'react'
export default class GetSnapshotBeforeUpdate extends Component {
myref = React.createRef()
state = {
list: [1,2,3,4,5,6,7,8,9,10]
}
getSnapshotBeforeUpdate() {
console.log(this.myref.current.scrollHeight)
// 获取容器高度
return this.myref.current.scrollHeight
}
componentDidUpdate(prevProps, prevState, value) {
console.log(this.myref.current.scrollHeight)
this.myref.current.scrollTop += this.myref.current.scrollHeight - value
}
render() {
return (
<div>
<button onClick={() => {
this.setState({
list: [...[11,12,13,14,15,16,17,18],...this.state.list]
})
}}>来消息</button>
<h1>消息通知</h1>
<div style={{height: "200px", overflow: "auto"}} ref={this.myref}>
<ul>
{
this.state.list.map((item, index) =>
<li key={index} style={{height: "100px", backgroundColor: 'yellow'}}>{item}</li>
)
}
</ul>
</div>
</div>
)
}
}
效果:
五、react生命周期性能优化
1、shouldComponentUpdate 控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下,需要进行优化。 2、PureComponent(在extends时不要继承Component,而是继承PureComponent) PureComponent会帮你比较新props和旧props,新的state和老的state(值相等,或者对象含有相同的属性,且属性值相等),决定shouldcomponentUpdate返回true或者false,从而决定要不要呼叫render 。(如果state和props永远都在变,那PureComponent并不会比较快,因为shallowEqual也需要花时间)
在学习React的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。