Как избежать сцепления при использовании useReducer? - PullRequest
1 голос
/ 03 апреля 2019

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

Представьте, например, компонент выбора даты. В какой-то момент этот компонент должен передать новое значение даты / времени вызывающему компоненту, чтобы данные могли быть сохранены (или как-то использованы). С помощью обратных вызовов у нас может быть простой реквизит, такой как saveDate={onSaveDate}. Выбор даты определяет контракт, говоря: «Я ожидаю, что эти реквизиты». В частности, я ожидаю saveDate реквизит с подписью newDate => {}. Этот поток имеет смысл для меня.

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

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

1 Ответ

1 голос
/ 04 апреля 2019

Я бы предложил отправлять карри с типом действия в родительском компоненте, например так:

const Parent = () => {
  const [state, dispatch] = useReducer(datepickerReducer, initialState)

  // might wanna useCallback here if your DatePicker is pure
  const changeDate = newDate => dispatch({ type: 'CHANGE_DATE', newDate })

  return <DatePicker onChange={changedate} value={state} />
}

Таким образом, ваш компонент остается изолированным от остальных, и вы можете использовать его так же, как и до хуков.Хотя, если вы часто используете datepickerReducer, это будет раздражать, когда каждый раз переопределять changeDate, поэтому я бы сделал свой собственный хук:

const useDatepicker = init => {
  const [date, dispatch] = useReducer(datepickerReducer)
  const changeDate = useCallback(newDate => dispatch({ type: 'CHANGE_DATE', newDate }), [])

  // I prefer using an object, makes it more convenient to reach values that would have been at the end of the array
  return { date, changeDate, /* You could have resetDate here aswell */ }
}

// USAGE
const { date, changeDate } = useDatepicker(new Date())

...