一直不能理解在新版本中componentWillReceiveProps
这个生命周期要被移除的原因,学艺不精啊,官方给出的componentWillReceiveProps
被调用是在props
发生改变的时候,感觉很合理啊,后来也是在官方早已经链接的相关博客里,找到了答案
class Component extends React.Component {
componentWillReceiveProps(nextProps) {
console.log('componentWillReceiveProps', nextProps.data.bar);
}
render() {
return <div>Bar {this.props.data.bar}!</div>;
}
}
var container = document.getElementById('container');
var mydata = {bar: 'drinks'};
ReactDOM.render(<Component data={mydata} />, container);
ReactDOM.render(<Component data={mydata} />, container);
ReactDOM.render(<Component data={mydata} />, container);
此时控制台会连续打印2次nextProps.data.bar
,原因很简单,React并不知道数据没有改变,且组件需要知道新的props
的值(即使它的值并没有改变),因此调用了生命周期componentWillReceiveProps
。
原文也解释了为什么React没有进行深比较的原因,考虑如下三种情况
- 传入复杂类型,如Object,当遇到嵌套层级较深时,React对其进行深比较的时候,开销会很大。
- 传入的时一些实例的时候,React也是无法比较的。
- 当传入的值为引用闭包的时候,React无法检查到相关内容。
当然上面给出的例子在我们日常开发中并不常见,我想到另外一个例子加以佐证:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
class Component extends React.PureComponent {
componentWillReceiveProps(nextProps) {
console.log("componentWillReceiveProps", nextProps.data.bar);
}
render() {
return <div>Bar {this.props.data.bar}!</div>;
}
}
function Example() {
const [count, setCount] = useState(0);
const data = { bar: "drinks" };
setInterval(() => {
setCount(count + 1);
}, 100);
return (
<div>
<Component data={data} />
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("root"));
或者
function Example() {
const [count, setCount] = useState(0);
const [data, setData] = useState("drinks")
const time = setTimeout(() => {
clearTimeout(time)
setCount(count + 1);
}, 100);
return (
<div>
<Component data={data} />
</div>
);
}
效果都是一样的,上面的例子中我们只是在更新state中count,导致父组件在rerender,子组件在不停的调用componentWillReceiveProps
方法
因而
componentWillReceiveProps
这个声明周期其实并不是向我们最初理解的那样,它会带来一些副作用,因而现在官方给出了三种替代它的方式:
- 一些有副作用的操作,如:操作dom,network request等放在
componentDidUpdate
里来执行 - 当因为
props
改变而导致需要重新计算一些数据当时候,可以写在memoization中 - 当需要
props
改变时更新state
的,可以放在完全受控组件中,或者通过key
来控制。
网友评论