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

Для новичков в React и хуках наступает момент, когда useState во всей красе не подходит для работы.

Более подробно о каждой части useReducer можно прочитать в статье. Сейчас я просто продемонстрирую, как useReducer может заменить несколько useStates формой ввода.

Начиная с useState

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

Мы инициализируем состояние имени пользователя пустой строкой в ​​строке 4, устанавливаем значение ввода в состояние имени пользователя в строке 13 и передаем анонимную функцию обратного вызова в onChange в строке 14, чтобы каждый раз, когда пользователь меняет входные данные, вызывается setUsername , обновляя состояние с вводом.

Пока что наше дружелюбное окружение useState кажется нормальным, оно выполняет нужную нам работу, но если форма вырастет еще на один ввод, мы вынуждены начать повторяться.

Вы можете себе представить, как это будет выглядеть, если мы хотим собрать какие-либо значимые данные от пользователя, для каждого ввода должен быть хук useState. Даже если наша форма легкая - скажем, нам просто нужно имя пользователя, адрес электронной почты, пароль и согласие пользователя - все наше состояние будет выглядеть примерно так.

const [username, setUsername] = useState(");
const [email, setEmail] = useState(");
const [password, setPassord] = useState(");
const [hasConsented, setHasConsented] = useState(false);

Хотя концептуально мы можем рассматривать нашу форму как одну большую часть состояния с несколькими полями, над которыми мы хотим контролировать. Именно для этого и предназначен useReducer! УРА. так что давайте посмотрим, как это может выглядеть.

С useReducer мы можем перепроектировать вышеупомянутое как единый объект начального состояния.

const initialFormState = {
                          username: "",
                          email: "",
                          password: "",
                          hasConsented: false,
                          };

useReducer записывается так:

const [state, dispatch] = useReducer(reducer, initialState);

где dispatch - это метод запуска обновлений / изменений состояния, reducer - это функция, которую мы определяем, которая управляет тем, как мы меняем состояние, а начальное состояние - это объект с определенными начальными значениями, как в примере initialFormState выше.

функция редуктора

Поскольку волшебство происходит в функции reducer, мы начнем с ее написания. Для клинической чистоты я собираюсь создать папку redurs с файлом formReducer.js.

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

В приведенном выше примере у нас есть два случая: «HANDLE INPUT TEXT», «TOGGLE CONSENT» и случай по умолчанию, который просто возвращает состояние как есть в случае, если action.type не соответствует / не определен.

В каждом случае мы возвращаем новый объект, используя оператор распространения (… состояние) для копирования всех свойств и значений из объекта состояния. Затем мы можем изменить значения определенных свойств состояния, явно объявив их снова с новым значением.

Пример «ПЕРЕКЛЮЧЕНИЕ СОГЛАСИЯ» может быть более очевидным, как это происходит. Мы снова объявляем свойство hasConsent и присваиваем ему значение, противоположное тому, что было раньше, переключая логическое значение с false на true или наоборот.

...
hasConsented: !state.hasConsented,
...

«HANDLE INPUT TEXT» работает аналогичным образом, но мы используем обозначение квадратных скобок, чтобы динамически объявлять, какое поле ввода мы изменяем на основе свойства field объекта действия. Затем мы устанавливаем значение этого значения, которое есть в нашем объекте действия.

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

С написанным редуктором давайте посмотрим, как это на самом деле меняет наш компонент формы, и мы можем использовать объекты действий.

Пример useReducer

Первое, что нужно сделать, это импортировать нашу функцию-редуктор, строка 3.

В строке 5 мы объявляем объект начального состояния, но он также может храниться отдельно и импортироваться, если вы того пожелаете. Живи своей лучшей жизнью.

В строке 13 мы деструктурируем наше состояние, которое будет использоваться, и метод отправки из хука useReducer с помощью функции-редуктора, которую мы написали, и начального состояния в качестве параметров.

Строка 15 Я написал функцию просто для того, чтобы навести порядок, когда мы переходим к нашим входам обработчика события onChange, он принимает событие (e) в качестве аргумента, который передается из onChange.

Действительно важная вещь - это отправка внутри функции. Метод отправки - это то, что отправляет объект действия в нашу функцию-редуктор. Здесь мы определяем, как должен выглядеть объект действия.

В нашем объекте у нас есть тип, поле, которое указывает, какой ввод мы будем изменять на основе свойства target.name события, и полезные данные. установлен в свойство target.value события. Нам просто нужно убедиться, что у наших входов есть атрибут имени, который соответствует ключу в объекте состояния.

На этом наш редуктор форм завершен! Booyah, теперь у нас есть один аккуратный объект состояния, который мы можем увеличивать или уменьшать по мере необходимости для управления входными данными в форме. Хук useReducer идеален для любого места, где ваше состояние может быть лучше всего смоделировано как объект, и он поддается написанию модульного кода, если вы к этому склонны.

Надеюсь, этот пример поможет дать некоторое представление о том, как useReducer может заменить несколько useStates, и побудит вас вскоре попробовать его в своих собственных проектах!