避免将 props 的值复制给 state!

前端精髓

共 2472字,需浏览 5分钟

 ·

2021-08-02 16:31


注意:避免将 props 的值复制给 state!这是一个常见的错误:


constructor(props) { super(props); // 不要这样做 this.state = { color: props.color };}


如此做毫无必要(你可以直接使用 this.props.color),同时还产生了 bug(更新 prop 中的 color 时,并不会影响 state)。


只有在你刻意忽略 prop 更新的情况下使用。此时,应将 prop 重命名为 initialColor 或 defaultColor。必要时,你可以修改它的 key,以强制“重置”其内部 state。


直接复制 prop 到 state


最常见的误解就是 getDerivedStateFromProps 和 componentWillReceiveProps 只会在 props “改变”时才会调用。实际上只要父级重新渲染时,这两个生命周期函数就会重新调用,不管 props 有没有“变化”。所以,在这两个方法内直接复制(unconditionally)props 到 state 是不安全的。这样做会导致 state 后没有正确渲染。


重现一下这个问题。这个 EmailInput 组件复制 props 到 state:


class EmailInput extends Component {  state = { email: this.props.email };
render() { return <input onChange={this.handleChange} value={this.state.email} />; }
handleChange = event => { this.setState({ email: event.target.value }); };
componentWillReceiveProps(nextProps) { // 这会覆盖所有组件内的 state 更新! // 不要这样做。 this.setState({ email: nextProps.email }); }}


乍看之下还可以。。state 的初始值是 props 传来的,当在 input 里输入时,修改 state。但是如果父组件重新渲染,我们输入的所有东西都会丢失!(查看这个示例),即使在重置 state 前比较 nextProps.email !== this.state.email 仍然会导致更新。


注意:示例中使用了 componentWillReceiveProps ,使用 getDerivedStateFromProps 也是一样。


getDerivedStateFromProps 的存在只有一个目的:让组件在 props 变化时更新 state。比如 props 的 offset 变化时,修改当前的滚动方向和根据 props 变化加载外部数据。


class ExampleComponent extends React.Component {  state = {    externalData: null,  };
static getDerivedStateFromProps(props, state) { // 保存 prevId 在 state 中,以便我们在 props 变化时进行对比。 // 清除之前加载的数据(这样我们就不会渲染旧的内容)。 if (props.id !== state.prevId) { return { externalData: null, prevId: props.id, }; } // 无需更新 state return null; }
componentDidMount() { this._loadAsyncData(this.props.id); }
componentDidUpdate(prevProps, prevState) { if (this.state.externalData === null) { this._loadAsyncData(this.props.id); } }
componentWillUnmount() { if (this._asyncRequest) { this._asyncRequest.cancel(); } }
render() { if (this.state.externalData === null) { // 渲染加载状态 ... } else { // 渲染真实 UI ... } }
_loadAsyncData(id) { this._asyncRequest = loadMyAsyncData(id).then( externalData => { this._asyncRequest = null; this.setState({externalData}); } ); }}


从 16.3 版本开始,当 props 变化时,建议使用新的 static getDerivedStateFromProps 生命周期更新 state。创建组件以及每次组件由于 props 或 state 的改变而重新渲染时都会调用该生命周期。




浏览 25
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报