Как уменьшить шаблонный код
Мы не будем здесь объяснять, как устроен redux и как он работает. Вы должны знать, что он использует действия и редукторы для управления состоянием, и большинство людей склонны использовать селекторы для чтения состояния из редукции.
вступление
Redux отлично подходит для управления вашим состоянием, но его можно легко перерасти в большой шаблонный код. Даже если вы пытаетесь управлять состоянием для разных вещей, имеющих схожий вариант использования, вы в конечном итоге создаете для них действия и редукторы.
Есть одно простое правило, которому я люблю следовать при работе над проектами react-redux. Если вы используете redux, используйте его везде! Не портите свой проект одними частями, которые используют состояние компонента, а другими - редукцией. Redux должен быть вашим «единственным источником истины». Не смешивайте это с setState
. Единственные части / компоненты, которые могут использовать состояния компонентов, - это те, которые могут быть повторно использованы в проектах, которые не используют redux. Они не должны иметь никакого отношения к логике вашего приложения.
Проблема
Учитывая все это, я попал в странную ситуацию. Во всех своих проектах я использую библиотеку Material-UI. Он использует такие компоненты, как текстовые поля, переключатели, диалоги и т. Д., Которые получают свойства. Хорошим примером является Dialog. Он сам управляет своим стилем, если он открыт или закрыт, но мы решаем с помощью свойств, когда он должен быть открыт или закрыт. Поскольку состояние, открыто ли диалоговое окно или нет, связано с логикой моего приложения, им нужно было управлять с помощью redux.
Потому что я использую диалоговое окно на 90% для отображения предупреждения об удалении типа «Вы действительно хотите удалить этот элемент / компанию / статью и т. Д.?» писать действия и редукторы для каждого из этих удалений было бы просто безумием. Поэтому создание одного действия и редуктора для управления всеми состояниями диалогов было для меня правильным решением. Это был очень простой редуктор, который запоминает для каждого диалога, открыт он или нет.
Это весь код действия:
import * as types from './types'; export function setDialogIsOpen(id, isOpen){ return { type: types.ON_DIALOG_OPEN_CHANGED, id, isOpen }; }
И это весь код редуктора:
import * as types from './types'; export default function dialogs(state={}, action){ switch (action.type) { case types.ON_DIALOG_OPEN_CHANGED: return {...state, [action.id]: action.isOpen}; default: return state; } }
Благодаря этому я мог управлять состоянием isOpen
для бесконечных диалогов в моем приложении, разделяя их по имени или идентификатору. У меня было хорошее и удобное решение.
Чтобы получить состояние isOpen
для моего диалогового компонента, мне просто нужно было проверить это следующим образом:
<Dialog title={intl.formatMessage({id: 'delete_task_title'})} actions={actions} modal={false} open={dialogs.delete_task===true} onRequestClose={this.handleClose}> {intl.formatMessage({id: 'delete_task_message'})} </Dialog>
Вы заметили, что весь чек равен dialogs.delete_task===true
. Диалог будет открыт, только если delete_task
был true
. Если он был undefined или false, он был бы закрыт.
У нас есть простое решение для состояний диалогового окна, но что с другими «простыми» состояниями, такими как текущая задача, показать или скрыть div, идентификатор выбранной строки и т. Д. Все те случаи, когда вам нужно сохранить только очень простое значение.
Решение
Решение такое же, как и для диалогового окна, но переименовано;)
Действие:
import * as types from './types'; export function setSimpleValue(id, value){ return { type: types.ON_SIMPLE_VALUE_CHANGED, id, value }; }
Редуктор:
import * as types from './types'; export default function simpleValues(state={}, action){ switch (action.type) { case types.ON_SIMPLE_VALUE_CHANGED: return {...state, [action.id]: action.value}; default: return state; } }
Он работает как диалоговое решение, но с переименованием, которое, как вы знаете, предназначено только для хранения простых значений. Его следует использовать только для «простых» значений! При хранении одиночных и простых значений, которые могут иметь только значение или нет, или могут быть просто true
или false
. Как только это усложнится с массивами, несколькими значениями, вы должны сделать отдельное действие и редуктор.
Все простые значения разделяются именами или идентификаторами. Такое решение просто использовать, но всегда есть риск опечаток, а повторение идентификатора имени / идентификатора может иметь странные побочные эффекты и ошибки.
Я бы рекомендовал использовать его на ранней стадии приложений, пока вы не на 100% уверены, какие действия и редукторы вам нужны. Очень удобно создавать простые прототипы без создания действий и редукторов.
Упорство
Если вы используете библиотеки сохраняемости, существует также «простое» решение. Просто создайте действие и редуктор, переименованные в persistentValues
, и используйте тот же код с переименованием. Большинство библиотек сохраняемости позволяют вам определять белый / черный список для определения того, должны ли части вашего состояния сохраняться или нет. Просто поместите simpleValues
в черный список или persistentValues
в белый список.
Демо
Если вам интересно, как все это работает, вы можете взглянуть на это в демонстрационном приложении, которое использует response, redux и firebase: ReactMostWanted