Рубрики
Без рубрики

Реагистрационный крюк для обработки состояния с зависимостями

Описание пользовательского реагированного крючка, который может упростить справиться с состоянием, который должен быть инициализирован и, потенциально недействительным на основе одной или нескольких зависимостей. Теги с реакцией, JavaScript, WebDev.

Для того, чтобы поэкспериментировать с New Cooks API React, я создавал приложение под названием Fretfull , что позволяет вам исследовать разные способы поиграть в аккорды на гитаре. Приложение Исходный код Использует крючки на протяжении всего для контекста и состояния.

Потрясая приложение, я создал что-то, что я называю «зависимым состоянием» пользовательского крючка. Это полезно, когда у вас есть часть состояния с диапазоном допустимых значений, которые рассчитываются на основе одной или нескольких зависимостей. Если изменения зависимости изменяются, текущее значение состояния больше не может быть действительным, и необходимо будет проверить и, возможно, сброс.

Чтобы сделать это более конкретным, рассмотрим следующую ситуацию:

  1. Приложение получает список категорий продуктов с сервера.
  2. Приложение отображает список категорий в UI.
  3. Пользователь выбирает категорию.
  4. Приложение получает обновленный список категорий с сервера.

На данный момент выбранная категория может или не может быть действительна, в зависимости от того, все еще существует в списке обновленных категорий. Следовательно, приложение должно быть умным о том, как он применяет обновление. Если категория больше не существует, сохранение его выбранного приведет к непоследовательному и неверному состоянию приложения. Однако автоматически сброс его приведет к плохому пользователю, если категория это все еще действует. Код должен будет проверить обновленный список и сброс выбора Только Если выбор не найден.

Давайте рассмотрим, как мы могли бы реализовать этот сценарий, используя реактивные крюки.

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”