需求
父组件有个对象类型的state变量会传给子组件,每次从父组件进入子组件这个变量都会重新set一次。子组件将这个prop作为某个uesEffect的依赖项,导致即使这个变量实际的值并没有发生变化,但由于每次父组件都会重新set,这个useEffect每次都会执行,所以希望可以将这个prop在子组件内部做一下转换,只有其值真的变化的时候才会执行这个useEffect。
初始方案
prop的类型定义
interface IPrecheckBeforeAddInstanceParams {
mysql_instance_id: string;
mysql_instance_umask: string;
mysql_instance_umask_dir: string;
server_id: string;
mysql_group_id: string;
}
解决方法
const precheckParamStr = React.useMemo(() => {
if (!props.installPrecheckParams) {
return '';
}
return JSON.stringify(props.installPrecheckParams);
}, [props.installPrecheckParams]);
将其从对象转换为字符串,将这个字符串作为依赖项,就可以避免不必要的重复执行
问题
序列化对象为字符串 不能保证它的正常执行,有隐形的强制条件。比如必须保证key的顺序也一致之类,或者后续需求中如果这个prop的结构产生了变化,则这段代码就无法继续正确运行了
最终解决方案
- 用一个ref保存每一次的prop值
- 用lodash库的
isEqual方法将ref保存的上一次的prop的值和当前prop的值进行比较 - 如果不相等才执行业务代码
const prevPropInstallPrecheckParamsRef =React.useRef<IPrecheckBeforeAddInstanceParams | null>(null);
React.useEffect(() => {
if (
!!props.installPrecheckParams &&
!isEqual(
prevPropInstallPrecheckParamsRef.current,
props.installPrecheckParams
)
) {
//执行业务代码
}
prevPropInstallPrecheckParamsRef.current = props.installPrecheckParams;
}, [props.isShow, props.installPrecheckParams]);