本文共 4322 字,大约阅读时间需要 14 分钟。
react v16.3 版本的发布,生命周期函数的变动去掉了以下三个
同时为了弥补失去上面三个周期的不足又加了两个
过度方案是在之前项目中使用去掉的函数添加前缀 UNSAFE_, 官网提示可以继续使用至 React 17。但在项目中依然会有一些waring ,建议修改。以下是项目中一些替换策略,涉及也是比较全面,且有我深入浅出一一阐述。
componentWillMount 函数中的场景有一下种:
在此方法中引入任何副作用或订阅。如遇此种情况,请改用 componentDidMount()
componentWillReceiveProps 函数在初始的props不会渲染。会在组件接受到新的 props 时调用。一般用于父组件更新状态时子组件的重新渲染。替换的场景如下:
替换策略:
如果您需要 执行副作用 (side effect)(例如,数据获取或动画)以响应 属性 (props) 的更改,使用 componentDidUpdate 生命周期方法
使用 componentWillReceiveProps, 在属性 (props) 改变 时重新计算一些数据,请使用 memoization 辅助工具-
使用 componentWillReceiveProps , 在属性 (props) 改变时 “重置” 一些 state (状态),考虑使用一个 完全控制组件 或 一个 带 key 的完全不受控 组件
可以使用 static getDerivedStateFromProps + componentDidUpdate vs getSnapshotBeforeUpdate + componentDidUpdate
以上3种情况是官网推荐, 也是比较简单的方式。static getDerivedStateFromProps 函数是官网也不推荐使用的函数,所以命名就比较长, 项目中对对此函数的替换在不拆分组件, 没有使用hook的情况下使用第3种策略进行的改写。
static getDerivedStateFromProps(props, state)
在调用 render 方法之前被调用,包括初始装载(mount)和后续更新时。 它应该返回一个更新 state (状态) 的对象,或者返回 null 以不更新任何 state (状态)。
getSnapshotBeforeUpdate(prevProps, prevState)
在最近一次的渲染输出被提交之前调用, 它返回的值将作为第三个 snapshot 参数传递给 componentDidUpdate() 。 否则这个参数将是 undefined componentDidUpdate(prevProps, prevState, snapshot)
此方法可以调用 setState()来操作 DOM 。但请注意,必须包含在条件语句中 像上面的例子一样,否则你会导致无限循环。 这也会导致额外的重新渲染, 虽然对用户不可见,但是会影响组件的性能。
例子1更改前
UNSAFE_componentWillReceiveProps(nextProps) { const { models = [], itemId, shopId } = nextProps.sellerData; const { itemId: currentItemId } = this.props.sellerData; if (itemId !== currentItemId && models.length && models.length > 0) { this.setState( { matchShop: {}, // 初始化state }, // callback 中调用 this.props 中父组件的方法 () => { this.init(models); this.props.onGetMatchingTable({ modelid: models[0].model_id, itemId, shopId }); } ); } }复制代码
例子1更改后
// getDerivedStateFromProps 接收最新的 Props 值 nextProps、上一个 state 值 prevState 两个参数,返回返回一个对象来更新 state,或者返回 null 表示不需要更新 state。 static getDerivedStateFromProps(nextProps, prevState) { const { models = [], itemId, shopId } = nextProps.sellerData; const { itemId: currentItemId } = (prevState && prevState.preSellerData) || ''; if ( currentItemId !== '' && itemId !== currentItemId && models.length && models.length > 0 ) { return { matchShop: {}, }; } return null; } componentDidUpdate(prevProps, prevState) { const { itemId: currentItemId } = prevProps.sellerData; const { models = [], itemId, shopId } = this.props.sellerData; if (itemId !== currentItemId && models.length && models.length > 0) { // console.log('prevState---this.props', this.props, prevState, prevProps); this.init(models); this.props.onGetMatchingTable({ modelid: models[0].model_id, itemId, shopId }); } }复制代码
例子2 state状态中iptUrl 是在子组件中,并且都多处可以变更,父组件传值props 用户可以输入url,这种情况下使用 getDerivedStateFromProps静态方法就会触发页面更改进入死循环。使用getSnapshotBeforeUpdate + componentDidUpdate进行替换修改。
// 更改前注释状态 // UNSAFE_componentWillReceiveProps(nextProps) { // if (nextProps.url !== this.state.iptUrl) { // this.setState({ // iptUrl: nextProps.url, // errMsg: '' // }); // } // } // 更改后 getSnapshotBeforeUpdate(prevProps, prevState) { if (prevProps.url !== this.props.url) { return this.props.url; } return null; } componentDidUpdate(prevProps, prevState, snapshot) { if (snapshot !== null) { this.setState({ iptUrl: this.props.url, errMsg: '' }); } }复制代码
在React 16.8 版本中可以使用 Effect Hook, useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。在hook 中没有生命周期的概念,更改数据的操作都可以称为副作用。Effect Hook 可以让你在函数组件中执行副作用操作。