十三、React生命周期函数
1.初始化阶段 (1)componentWillMount:render之前最后一次修改状态。注意:在react18之后被弃用了,如果想render之前最后一次修改状态只能在constructor里面进行修改 类似于vue的beforeMount,在这个阶段之前是constructor,但是constructor不属于生命周期函数。 (2)render:只能访问this.props和this.state,不允许修改状态和DOM (3)componentDidMount:成功render并渲染完成真实DOM之后,可以修改DOM。可以进行数据请求axios、订阅函数调用、setInterval定时器、基于创建的完的dom进行 初始化第三方组件(初始化只执行一次)
import React, { Component } from 'react'
export default class APP extends Component {
state = {
value: "123"
}
constructor() {
super()
console.log("constructor");
this.setState({
value: "zxc"
})
}
UNSAFE_componentWillMount() {
console.log("componentWillMount", this.state.value);
this.setState({
value: "asf"
})
}
componentDidMount() {
console.log("componentDidMount", this.state.value);
}
render() {
console.log("render", this.state.value);
return (
<div>APP</div>
)
}
}
2.运行中阶段(更新阶段) (1)shouldComponentUpdate:返回false会阻止render再次调用渲染页面。例如:我们点击按钮调用setState对状态进行修改,我们修改完之后,继续点击,会发现componentDidUpdate函数会一直打印出此DOM节点,页面一直重复渲染相同的内容,调用diff算法,所以防止这样,我们可以判断新的state状态和老的state状态是否一样。 (2)componentWillUpdate:render更新前,不能修改属性和状态,获取不到DOM (3)componentDidUpdate:可以修改DOM
import axios from 'axios'
import React, { Component } from 'react'
export default class App extends Component {
state = {
name: "xiaozhang",
list: []
}
componentDidMount() {
axios.get("/test.json").then((res) => {
this.setState({
list: res.data.data.films
})
})
}
render() {
return (
<div>
<button onClick={() => {
this.setState({
name: "lihua"
})
}}>click</button>
<span id="name">{this.state.name}</span>
<div id="warpper" style={{
height: "100px", overflow: "hidden", background: "yellow"
}}>
<ul>
{
this.state.list.map(item =>
<li key={item.filmId}>{item.name}</li>
)
}
</ul>
</div>
</div>
)
}
shouldComponentUpdate(nextProps, nextState) {
if (JSON.stringify(this.state) !== JSON.stringify(nextState)) {
return true
}
return false
}
UNSAFE_componentWillMount() {
console.log("componentWillUpdate", document.getElementById("name"))
}
componentDidUpdate(prevProps, prevState) {
console.log("componentDidUpdate", document.getElementById("name").innerHTML)
console.log(prevState.list)
if (prevState.list.length === 0) {
console.log("warpper");
}
}
}
案例:
import React, { Component } from 'react'
class Box extends Component {
shouldComponentUpdate(nextProps) {
if (this.props.current === this.props.index || nextProps.current === nextProps.index) {
return true
}
return false
}
render() {
console.log("render")
return <div style={{ width: "100px", height: "100px", border: this.props.current === this.props.index ? '1px solid red' : '1px solid gray', margin: "10px", float: 'left' }}>
</div>
}
}
export default class App extends Component {
state = {
list: ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09"],
current: 0
}
render() {
return (
<div>
<input type="number" onChange={(evt) => {
console.log(evt.target.value)
this.setState({
current: Number(evt.target.value)
})
}} value={this.state.current} />
<div style={{ overflow: "hidden" }}>
{
this.state.list.map((item, index) =>
<Box key={item} current={this.state.current} index={index} />
)
}
</div>
</div>
)
}
}
(4)componentWillReceiveProps:父组件修改属性触发,最先获得父组件传来的属性, 可以利用属性进行ajax或者逻辑处理。
import React, { Component } from 'react'
class Child extends Component {
state = {
title: ""
}
render() {
return <div>child-{this.state.title}</div>
}
componentWillReceiveProps(nextProps) {
console.log("componentWillReceiveProps", nextProps)
this.setState({
title: nextProps.text + "kerwin"
})
}
}
export default class App extends Component {
state = {
text: "11111111111"
}
render() {
return (
<div>
{
this.state.text
}
<button onClick={() => {
this.setState({
text: "222222222222"
})
}}>click</button>
<Child text={this.state.text} />
</div>
)
}
}
- 销毁阶段
(1)componentWillUnmount:在删除组件之前进行清理操作。比如定时器销毁和事件监听器解绑
import React, { Component } from 'react'
export default class App extends Component {
state = {
isCreated:true
}
render() {
return (
<div>
<button onClick={()=>{
this.setState({
isCreated:!this.state.isCreated
})
}}>click</button>
{}
{this.state.isCreated && <Child/>}
</div>
)
}
}
class Child extends Component{
render(){
return <div>
child
</div>
}
componentDidMount() {
window.onresize = ()=>{
console.log("resize")
}
this.timer = setInterval(()=>{
console.log("111")
},1000)
}
componentWillUnmount(){
console.log("componentWillUnmount")
window.onresize = null
clearInterval(this.timer)
}
}
老生命周期的问题:
(1) componentWillMount ,在ssr中这个方法将会被多次调用, 所以会重复触发多遍,同时在这里如果绑定事件, 将无法解绑,导致内存泄漏,变得不够安全高效逐步废弃。 (2) componentWillReceiveProps 外部组件多次频繁更新传入多次不同的 props,会导致不必要的异步请求 (3) componetWillupdate, 更新前记录 DOM 状态, 可能会做一些处理,与componentDidUpdate相隔时间如果过 长, 会导致 状态不太信
新生命周期
- getDerivedStateFromProps
getDerivedStateFromProps 本来(React v16.3中)是只在创建和更新(由父组件引发部分),也就是不是不由父组件引发,那么getDerivedStateFromProps也不会被调用,如自身setState引发或者forceUpdate引发 这样的话理解起来有点乱,在React v16.4中改正了这一点,让getDerivedStateFromProps无论是Mounting还是Updating,也无论是因为什么引起的Updating,全部都会被调用。 getDerivedStateFromProps(props, state) 在组件创建时和更新时的render方法之前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容
- getSnapshotBeforeUpdate
getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。
react中性能优化的方案
- shouldComponentUpdate
控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下, 需要进行优化
- PureComponent
PureComponent会帮你 比较新props 跟 旧的props, 新的state和老的state(值相等,或者 对象含有相同的属性、且属性值相等 ),决定shouldcomponentUpdate 返回true 或者 false, 从而决定要不要呼叫 render function。 注意: 如果你的 state 或 props 『永远都会变』,那 PureComponent 并不会比较快,因为 shallowEqual 也需要花时间。
|