Привет, ребята, сегодня я здесь, чтобы показать вам, как лучше структурировать редукторы без классического стиля switch-case, к которому так привязано большинство разработчиков, которых я видел до сегодняшнего дня.

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

Когда я показал свою структуру этому младшему разработчику (назовем его Боб), ему просто потребовалось очень много времени, чтобы понять, как все работает, в его голове, и, вероятно, для большинства новичков идея редуктора всегда привязана к переключателю. случай, что точно не правда, даже близко не то.

Итак, первое, что мы собираемся сделать, это точно определить, что такое редуктор:

Редуктор - это любая функция, которая получает состояние и возвращает новое на основе некоторой информации.

Основываясь на этой информации, мы можем точно объяснить примеры корпусов коммутаторов, не обращая внимания на их часть.

Это очень распространенный пример редуктора, и мы можем подтвердить, что он соответствует определению редуктора, он получает текущее состояние в качестве параметров и на основе некоторой информации (в данном случае типа действия) он возвращает новое состояние. Здесь я хочу уточнить, что switch-case используется только для удобства, он не является обязательным и не является лучшим способом определения нашей логики редуктора, мы могли бы переписать этот пример, просто используя if и else:

Это полностью приемлемо на основе определения редуктора, оно также принимает текущее состояние и возвращает новое на основе некоторой информации.

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

  • Многоразовый код
  • Легче понять
  • Легко извлечь логику в другой файл (мы увидим это позже)
  • Легче поддерживать в больших командах
  • Сосредоточьтесь на главном (логике), забудьте о корпусе выключателя

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

Итак, наш counterReducer выглядит так в новой структуре

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

Что это за странный синтаксис? а что такое объект обработчики? Отличный вопрос! в новой структуре мы заменяем переключатели для объектов, то есть объекта обработчиков, каждое отдельное свойство одного этого объекта является функцией, которая получает состояние и действие в качестве параметров.

Что такое функция reducerFactory? и что он получает в качестве параметров? Также отличный вопрос, ха-ха, эта функция отвечает за создание нашего редуктора на основе некоторого состояния и объекта обработчиков, поэтому каждый раз, когда редуктор вызывается, он будет проверять, существует ли обработчик, определенный для это действие, и если оно есть, новое состояние будет результатом этого обработчика. Это проще понять с помощью графика:

На этом графике мы можем точно понять, для чего reducerFactory, он получает действие, проверяет наличие обработчика для этого действия, и, если для этого есть какой-либо обработчик, он обновит состояние с помощью результат этого обработчика, иначе состояние не изменится.

Теперь посмотрим на код reducerFactory:

И все, ничего больше, в основном мы получаем initialState для нашего редуктора и объект-обработчик. Когда действие попадает в этот метод, мы получаем обработчик на основе action.type, и если обработчик не undefined, мы возвращаем его результат, передавая текущее состояние и полный действие в качестве параметров, иначе мы просто вернем текущее состояние, так как для этого действия не был определен обработчик.

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

Повторно используемый код и его легче понять

Что ж, это, безусловно, самые большие преимущества этого подхода, потому что мы не привязаны к одному императивному коду switch-case, вместо этого у нас есть вся мощь объектов в наших руках, мы можем определять обработчики и изменять их по мере необходимости, при необходимости, например, вы, вероятно, поймали себя на написании редукторов, которые просто получают какой-то объект и отправляют его в хранилище, что-то вроде

Во многих случаях это происходит, вы только что получили состояние действия и отправили его в магазин, не было ни проверки, ни побочных эффектов, вы просто хотели обновить магазин своими параметрами, и у вас было написать для этого много шаблонного кода. Размышляя об этих случаях, мы можем создать одну функцию changeState, которая делает именно это, и поскольку мы больше не привязаны к случаям переключения, это может быть функция генератора, которая получает только один параметр, например:

С помощью этой функции мы можем получить ту же самую логику, но с гораздо более читаемым стилем, конечный результат будет:

Это намного легче читать, и вам не потребовалось ни секунды, чтобы понять, что делает actions.SET_USER.

Легко извлечь логику в другой файл

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

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

Легче поддерживать в больших командах

Чем больше растет проект, тем больше конфликтов будет в репозитории, это не мое мнение, это чистая правда, если два человека работают над одним и тем же файлом одновременно, почти невозможно, чтобы конечный результат не сгенерировал новый конфликт в репозитории git, поэтому мы должны избегать любой ценой создания больших файлов кода, потому что чем больше файл, тем больше вероятность того, что два разработчика будут иметь задачи, связанные с изменением этого файла. С помощью этой структуры мы можем переместить логику обработчика в их собственный файл, избегая конфликтов в конечном результате, и если даже при этом возникнет какой-либо конфликт, его будет намного легче решить.

Сосредоточьтесь на главном

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

И последнее: все концепции, представленные здесь, работают с редукторами redux, а также с обработчиком реакции useReducer.

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