Допустим, у меня есть 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
также полезно для отслеживания изменений только локально, поэтому я могу предотвратить ненужный сетевой вызов из-за изменений с сервера.
источник
Ответы:
Вы можете написать собственный хук, чтобы предоставить вам предыдущий реквизит, используя useRef
а затем использовать его в
useEffect
Однако его все яснее и, вероятно, лучше и яснее читать и понимать, если вы используете два
useEffect
отдельно для каждого идентификатора изменения, который вы хотите обработать отдельно.источник
useEffect
вызовов отдельно. Не знал, что вы можете использовать его несколько раз!useEffect
отсутствуют зависимостиprevAmount
Incase кто-нибудь ищет версию использования TypeScriptPrevious:
источник
const usePrevious = <T extends any>(...
чтобы заставить интерпретатора думать, что <T> не является JSX и является общим ограничением<T extends {}>
не будет работать. Кажется, это работает для меня, но я пытаюсь понять сложность такого использования..tsx
файлы содержат jsx, который должен быть идентичным html. Возможно, что универсальный<T>
является незакрытым тегом компонента.Missing return type on function.eslint(@typescript-eslint/explicit-function-return-type)
Вариант 1 - использовать крючок
Сравнение текущего значения с предыдущим значением является распространенным шаблоном и оправдывает собственную собственную ловушку, которая скрывает детали реализации.
демонстрация
Вариант 2 - запустить useEffect при изменении значения
демонстрация
источник
Я только что опубликовал ответную дельту, которая решает именно этот сценарий. На мой взгляд,
useEffect
слишком много обязанностей.обязанности
Object.is
Распределение обязанностей
react-delta
разбиваетuseEffect
обязанности на несколько более мелких зацепок.Ответственность № 1
usePrevious(value)
useLatest(value)
useDelta(value, options)
useDeltaArray(valueArray, options)
useDeltaObject(valueObject, options)
some(deltaArray)
every(deltaArray)
Ответственность № 2
useConditionalEffect(callback, boolean)
По моему опыту, этот подход более гибкий, чистый и лаконичный, чем
useEffect
/useRef
решения.источник
Поскольку состояние не тесно связано с экземпляром компонента в функциональных компонентах, предыдущее состояние не может быть достигнуто
useEffect
без предварительного его сохранения, например, с помощьюuseRef
. Это также означает, что обновление состояния, возможно, было неправильно выполнено в неправильном месте, потому что предыдущее состояние доступно внутриsetState
функции обновления.Это хороший пример использования,
useReducer
который предоставляет Redux-подобное хранилище и позволяет реализовать соответствующий шаблон. Обновления состояний выполняются явно, поэтому нет необходимости выяснять, какое свойство состояния обновляется; это уже ясно из отправленных действий.Вот пример того, как это может выглядеть:
источник
sendAmount
и т. Д. Асинхронно, а не вычислять их, верно? Это сильно меняется. Это возможно сделать,useReduce
но может быть сложно. Если вы имели дело с Redux до того, как узнаете, что асинхронные операции не так просты. github.com/reduxjs/redux-thunk - это популярное расширение для Redux, которое позволяет выполнять асинхронные действия. Вот демонстрация, которая расширяет useReducer с тем же шаблоном (useThunkReducer), codesandbox.io/s/6z4r79ymwr . Обратите внимание, что отправленная функция естьasync
, вы можете делать запросы там (закомментировано).Использование Ref внесет новый вид ошибок в приложение.
Давайте посмотрим на этот случай, используя
usePrevious
то, что кто-то прокомментировал ранее:Как мы видим здесь, мы не обновляем внутреннее,
ref
потому что мы используемuseEffect
источник
state
... а неprops
... когда вы заботитесь о старых подпорках, тогда произойдет ошибка.Для действительно простого сравнения реквизитов вы можете использовать useEffect, чтобы легко проверить, обновился ли реквизит.
Затем useEffect будет запускать ваш код только при изменении реквизита.
источник
prop
изменений вы не сможете~ do stuff here ~
setHasPropChanged(false)
в конце,~ do stuff here ~
чтобы "сбросить" ваше состояние. (Но это сбросило бы в дополнительном повторном рендере)Отход от принятого ответа, альтернативное решение, которое не требует пользовательского хука:
источник
useRef
неuserRef
. Забыл использовать токprevAmount.current
Вот пользовательский хук, который я использую, который я считаю более интуитивным, чем использование
usePrevious
.Вы бы использовали
useTransition
следующим образом.Надеюсь, это поможет.
источник