仅当两个依赖性变化时运行效果钩



我有一个反应组件,可以使用 useEffect钩子拿出数据:

const cache = {key: "data-fetched-using-key"}
function Config({key, options}) {
    const [data, setData] = useState();
    useEffect(() => {
        const fetchedData; // fetch data using key and options
        setData(fetchedData);
        cache[key] = fetchedData;
    }, [key, options])
    return <p>{data}</p>;
}

每次keyoptions更改时,都会运行挂钩。但是,我也在本地缓存数据,并且只希望在keyoptions更改时效果(因为对于每个键/选项组合,数据始终是相同的(。

使用React Hooks?

,有没有一种干净的方法来依赖keyoptions的组合而不是keyoptions

您可以使用useRef()创建这种逻辑。考虑以下示例和沙箱:https://codesandbox.io/s/reaect-hooks-hooks-useeffect-with-multiple-reqs-6ece5

const App = () => {
  const [name, setName] = useState();
  const [age, setAge] = useState();
  const previousValues = useRef({ name, age });
  useEffect(() => {
    if (
      previousValues.current.name !== name &&
      previousValues.current.age !== age
    ) {
      //your logic here
      console.log(name + " " + age);
      console.log(previousValues.current);
      //then update the previousValues to be the current values
      previousValues.current = { name, age };
    }
  });
  return (
    <div>
      <input
        placeholder="name"
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <input
        placeholder="age"
        value={age}
        onChange={e => setAge(e.target.value)}
      />
    </div>
  );
};

工作流:

  1. 我们为要跟踪的两个值创建一个ref对象,在这种情况下,它的nameage。REF对象是previousValues
  2. useEffect已定义,但我们没有提供任何依赖项。相反,只要有状态变化,我们只是执行 nameage
  3. 现在在useEffect中,我们有条件逻辑来检查是否是nameage的先前/初始值都不同他们相应的国家价值。如果他们很好,那么我们执行我们的逻辑(console.log)
  4. 最后执行逻辑后,将REF对象(previousValues)更新为当前值(state)

为了在两个值变化时运行效果,您需要使用先前的值并在键或选项更改时将它们在钩子中进行比较。

您可以编写 usePrevious钩子并比较本文中提到的旧状态和以前的状态:

如何比较React Hooks使用效果的OldValues和NewValues?

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}
const cache = {key: "data-fetched-using-key"}
function Config({key, options}) {
    const [data, setData] = useState();
    const previous = usePrevious({key, options});
    useEffect(() => {
        if(previous.key !== key && previous.options !== options) {
            const fetchedData; // fetch data using key and options
            setData(fetchedData);
            cache[key] = fetchedData;
        }
    }, [key, options])
    return <p>{data}</p>;
}

所有提供的解决方案都很好,但是,只有在依赖性a和b更改时才能调用使用效率函数时,有一些更复杂的情况,而这也取决于C的值。

因此,我建议使用一系列使用效应和中间状态为将来的逻辑提供更多空间。该方法的实施将是:

const cache = {key: "data-fetched-using-key"}
function Config({key, options}) {
    const [data, setData] = useState();
    const [needsUpdate, setNeedsUpdate] = useState(()=>({key:false, option:false}));
    useEffect(()=>{
      setNeedsUpdate((needsUpdate)=>({...needsUpdate, key:true}));
    },[key])
    useEffect(()=>{
      setNeedsUpdate((needsUpdate)=>({...needsUpdate, options:true}));
    },[options])
    useEffect(() => {
      if (needsUpdate.key && needsUpdate.options){
        const fetchedData; // fetch data using key and options
        setData(fetchedData);
        cache[key] = fetchedData;
        setNeedsUpdate(()=>({key:false, option:false}));
      }
    }, [needsUpdate, key, options])
    return <p>{data}</p>;
}

通过这种方式,我们几乎可以对我们的使用效率依赖性应用任何逻辑,但是它具有自己的缺点,这是更多的渲染周期。

您可以创建一个新的自定义挂钩,该挂接带有带有索引/依赖项名称的参数

的参数
const useChangesEffect = (callback, dependencies, dependencyNames = null) => {
  const prevValues = useRef(dependencies);
  useEffect(() => {
    const changes = [];
    for (let i = 0; i < prevValues.current.length; i++) {
      if (!shallowEqual(prevValues.current[i], dependencies[i])) {
        changes.push(dependencyNames ? dependencyNames[i] : i);
      }
    }
    callback(changes);
    prevValues.current = dependencies;
  }, dependencies);
};

useChangesEffect((changes) => {
  if (changes.includes(0)) {
    console.log('dep1 changed');
  }
  if (changes.includes(1)) {
    console.log('dep2 changed');
  }
}, [dep1, dep2]);

最新更新