Для того, чтобы поэкспериментировать с New Cooks API React, я создавал приложение под названием Fretfull , что позволяет вам исследовать разные способы поиграть в аккорды на гитаре. Приложение Исходный код Использует крючки на протяжении всего для контекста и состояния.
Потрясая приложение, я создал что-то, что я называю «зависимым состоянием» пользовательского крючка. Это полезно, когда у вас есть часть состояния с диапазоном допустимых значений, которые рассчитываются на основе одной или нескольких зависимостей. Если изменения зависимости изменяются, текущее значение состояния больше не может быть действительным, и необходимо будет проверить и, возможно, сброс.
Чтобы сделать это более конкретным, рассмотрим следующую ситуацию:
- Приложение получает список категорий продуктов с сервера.
- Приложение отображает список категорий в UI.
- Пользователь выбирает категорию.
- Приложение получает обновленный список категорий с сервера.
На данный момент выбранная категория может или не может быть действительна, в зависимости от того, все еще существует в списке обновленных категорий. Следовательно, приложение должно быть умным о том, как он применяет обновление. Если категория больше не существует, сохранение его выбранного приведет к непоследовательному и неверному состоянию приложения. Однако автоматически сброс его приведет к плохому пользователю, если категория это все еще действует. Код должен будет проверить обновленный список и сброс выбора Только Если выбор не найден.
Давайте рассмотрим, как мы могли бы реализовать этот сценарий, используя реактивные крюки.
function Categories({ apiData }: { apiData: CategoriesApiResult }) {
const categories = useMemo(() => {
return apiData.data.map(cat => cat.name);
}, [apiData]);
const [category, setCategory] = useState(categories[0]);
return setCategory(e.value)}
/>;
}
Здесь компонент категорий создает список вариантов категории, сопоставив данные из вызова API, полученным в виде опоры. Мы воспоминаем расчет, поэтому он выполняется только при изменении данных API. Мы также храним выбранную категорию в качестве части состояния, по умолчанию по умолчанию до первой категории в списке.
Тем не менее, этот код имеет ошибку: если Категории изменения, стоимость категория больше не может быть действительным. Нам нужно проверить, что все еще действует и, необязательно, сброс его. Мы можем сделать это следующим образом:
let [category, setCategory] = useState(null);
const categories = useMemo(() => {
const result = apiData.data.map(cat => cat.name);
if (!result.includes(category) {
setCategory(category = result[0]);
}
}, [apiData]);
Теперь мы избегаем ошибки, но за счет самозагрузится на нашу логику рендеринга. Мы должны сделать категория переназначен, определить его раньше Категории и включите побочный эффект в нашем категории Функция памяти, которая сбрасывает категория .
Мы можем сделать этот подход более чистым и более многоразовым, реализуя пользовательский крюк, который мы позвоним УрезундидентныйЗеденционировать :
function useDependentState( factory: (prevState?: S) => S, inputs: ReadonlyArray, ): [S, Dispatch >] { let [state, setState] = useState (factory()); useMemo(() => { const newState = factory(state); if (newState !== state) { setState(state = newState); } }, inputs); return [state, setState]; }
Этот крючок отражает сущность вышеуказанной логики в общем виде. Он определяет кусочек состояния и запускает воменевшую функцию, которая проходит только при изменении зависимостей. Эта метеорезированная функция делегаты к заводской функции, которую мы должны предоставить, и которая несет ответственность за создание начального значения, либо изменение текущего значения, если он больше не действителен. Давайте посмотрим, как мы могли бы использовать его в предыдущем примере:
const categories = useMemo(() => {
return apiData.data.map(cat => cat.name);
}, [apiData]);
const [category, setCategory] = useDependentState(prevState => {
return (prevState && categories.includes(prevState)) ?
prevState
:
categories[0];
}, [categories]);
Наш пользовательский крючок означает, что мы можем сохранить категория Как Const, сохраните оригинальный порядок определения, и единственная логика, которую мы должны реализовать, – это чек для того, является ли Превзойти Значение все еще действует.
Вывод
Надеюсь, этот пользовательский крючок может оказаться полезным для всех, кто сталкивается с аналогичным вопросом с государством, чей зависит от некоторых зависимостей.
Единственный недостаток я вижу к этому пользовательскому крюку, это то, что он должен позвонить SetState Чтобы обновить значение состояния, когда он меняется, что приведет к второму визуализации. Но я не вижу никакого способа избежать этого. У меня есть Представил предложение объекта реагирования С идеей повышения регулярных SetState Крюк с возможностью обеспечения зависимостей, которые привели к тому, что он будет повторно инициализирован аналогичным образом к этому пользовательскому крюку. Если реализовано, это устранит необходимость дополнительного визуализации, как Превзойти Значение не было бы “утечка”, потому что логика проверки будет происходить в пределах Уместите вызов.
Оригинал: “https://dev.to/jonrimmer/a-react-hook-to-handle-state-with-dependencies-2dl1”