Запускать ловушку Effect только при изменении обеих зависимостей - PullRequest
4 голосов
/ 04 июля 2019

У меня есть компонент React, который извлекает данные с помощью хука 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>;
}

Это запускает ловушку каждый раз, когда key или options изменяются. Однако я также кеширую данные локально и хочу, чтобы эффект запускался только при изменении key И options (поскольку для каждой комбинации клавиш / опций данные всегда будут одинаковыми).

Есть ли чистый способ зависеть от комбинации key И options, а не key ИЛИ options с использованием React Hooks?

Ответы [ 2 ]

3 голосов
/ 04 июля 2019

Чтобы запустить эффект при изменении обоих значений, вам нужно использовать предыдущие значения и сравнивать их внутри ловушки при изменении ключа или опций

Для этого:Вы можете написать ловушку usePrevious и сравнить старое и предыдущее состояние, как упомянуто в этом сообщении

Как сравнить oldValues ​​и newValues ​​в React Hooks useEffect? ​​

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>;
}
3 голосов
/ 04 июля 2019

Вы можете создать такую ​​логику с помощью useRef(). Рассмотрим следующий пример и песочницу: https://codesandbox.io/s/react-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>
  );
};

Workflow:

  1. Мы создаем объект ref для двух значений, которые мы хотим отслеживать, в этом случае это name и age. Ссылочный объект previousValues.
  2. useEffect определен, но мы не предоставляем ему никаких зависимостей. Вместо этого мы просто выполняем его всякий раз, когда происходит изменение состояния на name или age.
  3. Теперь внутри useEffect у нас есть условная логика, чтобы проверить, предыдущие / начальные значения name и age отличаются от их соответствующие значения состояния. Если они хороши, мы выполняем наша логика (console.log).
  4. Наконец, после выполнения логики, обновите объект ref (previousValues) до текущих значений (state).
...