如何比较某个prop对象前后是否一致

65 阅读1分钟

需求

父组件有个对象类型的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的结构产生了变化,则这段代码就无法继续正确运行了

最终解决方案

  1. 用一个ref保存每一次的prop值
  2. 用lodash库的isEqual方法将ref保存的上一次的prop的值和当前prop的值进行比较
  3. 如果不相等才执行业务代码
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]);