react 生命周期函数变更
react v16.3 版本的发布,生命周期函数的变动去掉了以下三个
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
同时为了弥补失去上面三个周期的不足又加了两个
- static getDerivedStateFromProps
- getSnapshotBeforeUpdate
过度方案是在之前项目中使用去掉的函数添加前缀 UNSAFE_, 官网提示可以继续使用至 React 17。但在项目中依然会有一些waring ,建议修改。以下是项目中一些替换策略,涉及也是比较全面,且有我深入浅出一一阐述。
UNSAFE_componentWillMount 的替换
componentWillMount 函数中的场景有一下种:
- class component中state 初始化数据状态的设置
- 官网建议使用 constructor() 来初始化 state。
- 异步拉取数据
- 可以放在componentDidMount 函数中 引用官网原句
在此方法中引入任何副作用或订阅。如遇此种情况,请改用 componentDidMount()
- 可以放在componentDidMount 函数中 引用官网原句
- 定时器
- 可以在 componentDidMount 函数中
- 另一种方式是把定时器的抽离新的子组件(涉及业务逻辑的都可以放在子组件中)
UNSAFE_componentWillReceiveProps 的替换
componentWillReceiveProps 函数在初始的props不会渲染。会在组件接受到新的 props 时调用。一般用于父组件更新状态时子组件的重新渲染。替换的场景如下:
- 对比 this.prop和nextProps
- 根据 nextProps更新state的操作 (见例子2)
- 不影响dom界面的显示
- 影响dom界面的显示
- 根据 nextProps更新state,并且有调用this.props的操作(见例子1)
替换策略:
-
如果您需要 执行副作用 (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: '' });
}
}
复制代码
使用 Effect Hook
在React 16.8 版本中可以使用 Effect Hook, useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。在hook 中没有生命周期的概念,更改数据的操作都可以称为副作用。Effect Hook 可以让你在函数组件中执行副作用操作。
参考
作者:yanziNote
链接:https://juejin.im/post/5df1e109f265da33bc57d753
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。