Как сравнить oldValues ​​и newValues ​​в React Hooks useEffect? - PullRequest
0 голосов
/ 23 ноября 2018

Допустим, у меня есть 3 входа: скорость, sendAmount и receiveAmount.Я поставил эти 3 входа на использование различных параметров.Правила:

  • Если sendAmount изменился, я вычисляю receiveAmount = sendAmount * rate
  • Если полученная сумма изменилась, я вычисляю sendAmount = receiveAmount / rate
  • Если ставка изменилась, я вычисляю receiveAmount = sendAmount * rate когда sendAmount > 0 или я вычисляю sendAmount = receiveAmount / rate когда receiveAmount > 0

Вот коды и поле https://codesandbox.io/s/pkl6vn7x6j, чтобы продемонстрировать проблему.

Есть ли способсравнить oldValues и newValues как на componentDidUpdate вместо создания 3 обработчиков для этого случая?

Спасибо


Вот мое окончательное решение с usePrevious https://codesandbox.io/s/30n01w2r06

В этом случае я не могу использовать несколько useEffect, потому что каждое изменение приводит к одному и тому же сетевому вызову.Вот почему я также использую changeCount, чтобы отслеживать изменения тоже.Это changeCount также полезно для отслеживания изменений только локально, поэтому я могу предотвратить ненужный сетевой вызов из-за изменений с сервера.

Ответы [ 3 ]

0 голосов
/ 23 ноября 2018

Поскольку состояние не тесно связано с экземпляром компонента в функциональных компонентах, предыдущее состояние не может быть достигнуто в useEffect без его предварительного сохранения, например, с помощью useRef.Это также означает, что обновление состояния, возможно, было неправильно реализовано в неправильном месте, потому что предыдущее состояние доступно внутри setState функции обновления.

Это хороший вариант использования для useReducer, который предоставляет Redux-подобное хранилище и позволяетреализовать соответствующий шаблон.Обновления состояний выполняются явно, поэтому нет необходимости выяснять, какое свойство состояния обновляется;это уже ясно из отправленного действия.

Вот пример как это может выглядеть:

function reducer({ sendAmount, receiveAmount, rate }, action) {
  switch (action.type) {
    case "sendAmount":
      sendAmount = action.payload;
      return {
        sendAmount,
        receiveAmount: sendAmount * rate,
        rate
      };
    case "receiveAmount":
      receiveAmount = action.payload;
      return {
        sendAmount: receiveAmount / rate,
        receiveAmount,
        rate
      };
    case "rate":
      rate = action.payload;
      return {
        sendAmount: receiveAmount ? receiveAmount / rate : sendAmount,
        receiveAmount: sendAmount ? sendAmount * rate : receiveAmount,
        rate
      };
    default:
      throw new Error();
  }
}

function handleChange(e) {
  const { name, value } = e.target;
  dispatch({
    type: name,
    payload: value
  });
}

...
const [state, dispatch] = useReducer(reducer, {
  rate: 2,
  sendAmount: 0,
  receiveAmount: 0
});
...
0 голосов
/ 29 июня 2019

Вариант 1 - ловушка useCompare

Сравнение текущего значения с предыдущим значением является распространенным шаблоном и оправдывает собственный собственный крючок, который скрывает детали реализации.

const useCompare = (val: any) => {
    const prevVal = usePrevious(val)
    return prevVal !== val
}

const usePrevious = (value) {
    const ref = useRef();
    useEffect(() => {
      ref.current = value;
    });
    return ref.current;
}

const Component = (props) => {
  ...
  const hasVal1Changed = useCompare(val1)
  const hasVal2Changed = useCompare(val2);
  useEffect(() => {
    if (hasVal1Changed ) {
      console.log("val1 has changed");
    }
    if (hasVal2Changed ) {
      console.log("val2 has changed");
    }
  });

  return <div>...</div>;
};

Демонстрация

Опция 2 - запустить useEffect при изменении значения

const Component = (props) => {
  ...
  useEffect(() => {
    console.log("val1 has changed");
  }, [val1]);
  useEffect(() => {
    console.log("val2 has changed");
  }, [val2]);

  return <div>...</div>;
};

Демонстрация

0 голосов
/ 23 ноября 2018

Вы можете написать собственный хук, чтобы предоставить вам предыдущий реквизит, используя useRef

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

, а затем использовать его в useEffect

const Component = (props) => {
    const {receiveAmount, sendAmount } = props
    const prevAmount = usePrevious({receiveAmount, sendAmount});
    useEffect(() => {
        if(prevAmount.receiveAmount !== receiveAmount) {

         // process here
        }
        if(prevAmount.sendAmount !== sendAmount) {

         // process here
        }
    }, [receiveAmount, sendAmount])
}

Однако его все яснее и, вероятно, лучше и яснее читать и понимать, если вы используете два useEffect отдельно для каждого идентификатора изменения, который вы хотите обработать отдельно

...