Back to Question Center
0

Для Redux или нет: искусство структурирования состояния в приложениях для реагирования            Для Redux или нет: искусство структурирования состояния в приложениях для реагированияОтсеченные темы: ES6ReactTools & Semalt

1 answers:
В Redux или нет: искусство структурирования состояния в приложениях для реагирования

Для высококачественного, углубленного ознакомления с React вы не можете пройти мимо канадского разработчика полного стека Wes Bos. Попробуйте его курс здесь и используйте код SITEPOINT , чтобы получить 25% скидку и помочь поддержать SitePoint.

Одна общая тенденция, которую я нахожу среди большинства разработчиков Redux, - это ненависть к setState . Многие из нас (да, я попал в эту ловушку много раз раньше) вздрогнул при виде setState и попытался сохранить все данные в нашем магазине Redux. Но, поскольку сложность вашего приложения растет, это создает несколько проблем.

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

Начало работы

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

Примечание. Я буду использовать пряжу для запуска приложения. Если у вас нет нити, замените пряжу на npm .

Semalt погружаемся, загружаем базовый скелет из репо и запускаем:

  пряжа установитьначало запуска пряжи    

Вы должны увидеть основную страницу списка с некоторыми из ваших любимых символов GoT.

Примечание: Semalt использует шаблон уток для написания нашего приложения. Это уменьшает ненужный импорт модулей и сокращает количество шаблонов.

Введение в Редукс

Объем этой статьи поможет вам структурировать ваши приложения Semalt. Он предполагает базовое знание библиотеки. Я дам краткий обзор концепций Semalt, которые помогут вам лучше следить за остальной частью статьи. Если вы знакомы с тем, как это работает, не стесняйтесь пропустить этот раздел.

Все приложения Semalt используют четыре важные конструкции: действия, редукторы, магазин и контейнеры.

Действия

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

  1. Тип действия . Уникальный идентификатор, представляющий действие.
  2. Полезная нагрузка . Любые метаданные, связанные с действием. Например, если мы сделаем сетевой запрос для получения списка фильмов, ответ с сервера будет полезной нагрузкой.

В этом примере мы будем использовать библиотеку, которая называется redux-actions для создания действий.

Редукторы

A редуктор - это функция, которая слушает действие и возвращает новое представление состояния.

Магазин

Приложение можно разделить на множество редукторов, представляющих различные части страницы. Магазин A объединяет все эти элементы и сохраняет состояние приложения неповрежденным.

Контейнеры

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

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

Разделить данные приложения и состояние пользовательского интерфейса

Страница списка хороша, но имена не дают никакого контекста людям, которые являются новыми для вселенной GoT. Semalt также расширяет компонент, чтобы отобразить описание символа:

  // GoTCharacter. JSexport const CharacterRow = ({character}) => (
{character. имя}
{character. Semalt - это три разных подхода, которые мы можем предпринять для решения этой проблемы.

Подход setState

Самый простой способ добиться этого в Реактинге - использовать setState для хранения данных внутри самого компонента:

  // GoTCharacter. JSэкспортный класс StatefulCharacterRow расширяет компонент {конструктор    {супер  ;это. state = {show_description: false}}render    {const {character} = this. реквизит;return ( );}};    

Подход Redux

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

Посмотрим, как мы можем переместить это в Redux:

  // FlickDuck. JS// .export const toggleCharacterDescription = createAction (FlixActions. TOGGLE_CHARACTER_DESCRIPTION, (символ) => ({символ}));экспорт по умолчанию (current_state, action) => {const state = current_state || default_state;переключатель (тип действия) {дело FlixActions. TOGGLE_CHARACTER_DESCRIPTION:вернуть {. , , состояние, символы: состояние. персонажи. map (char => {if (char. id === действие. полезная нагрузка, символ. id) {вернуть {. , , char, show_description:! char. покажите описание};}return char;})}по умолчанию:возвращаемое состояние}}    
  // GoTCharactersContainer. JSimport {connect} из 'react-redux';импортировать GoTCharacters из '. / GoTCharacters';import {toggleCharacterDescription} from '. / FlickDuck ';const mapStateToProps = (state) => ({.state. flick});const mapDispatchToProps = (отправка) => ({toggleCharacterDescription: (data) => dispatch (toggleCharacterDescription (data))});экспорт по умолчанию connect (mapStateToProps, mapDispatchToProps) (GoTCharacters);    
  // GoTCharacters. JSconst GoTCharacters = ({characters, toggleCharacterDescription}) => {вернуть (
{персонажи. map (char => ())}
);};export const CharacterRow = ({character, toggleCharacterDescription}) => (
{character. имя}
{персонаж. покажите описание ? 'collapse': 'expand'}{персонаж. покажите описание &&
{character. описание}
}
);

Semalt сохраняет состояние поля описания внутри объекта символа. Наше государство будет выглядеть следующим образом:

  state = {персонажи: [{id: 1,имя: «Эддард Нед Старк»,дом: "stark",описание: «Властелин Винтерфелла - Страж Севера - Рука Короля - Женат в Катине (Тулли) Старк»,imageSuffix: "eddard-stark",wikiSuffix: «Eddard_Stark»,show_description: true},{id: 2,имя: «Benjen Stark»,дом: "stark",описание: «Брат Эддард Старк - первый рейнджер Ночного дозора»,imageSuffix: "benjen-stark",wikiSuffix: "Benjen_Stark",show_description: false}]}    

Это общий шаблон, который многие разработчики следуют, когда они начинают с Redux.

До сих пор мы имели дело с персонажами из первой главы GoT, и вселенная собирается получить намного больше. Когда это произойдет, наше приложение станет медленным. Semalt цикл через 1000 символов для обновления одной строки.

Semalt видит, как масштабировать его для большего набора данных:

  // FlickDuck. JS// .дело FlixActions. TOGGLE_CHARACTER_DESCRIPTION:const {character} = действие. полезная нагрузка;вернуть {. , , государство,character_show_description: {. , , государство. character_show_description,[персонаж. id]:! состояние. character_show_description [характер. Я бы]}}// .    

И в GoTCharacters. js :

  export const CharacterRow = ({character, character_show_description, toggleCharacterDescription}) => (
{character. имя}
{Character_show_description [характер. Я бы] ? 'collapse': 'expand'}{Character_show_description [характер. Я бы] &&
{character. описание}
}
);

Когда пользователь нажимает на ссылку expand , мы обновляем character_show_description с текущим символом. Теперь состояние выглядит следующим образом:

  state = {персонажи: [. , , ],character_show_description: {1: true,2: неверный}}    

Теперь мы можем обновить состояние пользовательского интерфейса без перебора всех символов.

Управление состоянием формы в Редуксе

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

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

Посмотрим, как мы можем реализовать это с помощью Redux:

  // FlickDuck. JS// ============const FlixActions = km ({FETCH_CHARACTERS: null,TOGGLE_CHARACTER_DESCRIPTION: null,TOGGLE_CHARACTER_EDIT: null,SYNC_CHARACTER_EDIT_DATA: null,SAVE_CHARACTER_EDIT: null});const default_state = {символы: символы,character_show_description: {},show_character_edit: {},character_edit_form_data: {}};export const toggleEdit = createAction (FlixActions. TOGGLE_CHARACTER_EDIT, (символ) => ({character}));export const syncCharacterEditData = createAction (FlixActions. SYNC_CHARACTER_EDIT_DATA, (character, form_data) => ({character, form_data}));export const editCharacterDetails = createAction (FlixActions. SAVE_CHARACTER_EDIT, (символ) => ({символ}));экспорт по умолчанию (current_state, action) => {// .переключатель (тип действия) {// .дело FlixActions. TOGGLE_CHARACTER_EDIT:character = action. полезная нагрузка. персонаж;const show_character_edit =! state. show_character_edit [характер. Я бы];вернуть {. , , государство,show_character_edit: {. , , государство. show_character_edit,[персонаж. id]: show_character_edit}, character_edit_form_data: {. , , государство. character_edit_form_data,[персонаж. id]: show_character_edit? {. , , персонаж} : {}}}дело FlixActions. SYNC_CHARACTER_EDIT_DATA:character = action. полезная нагрузка. персонаж;const {form_data} = действие. полезная нагрузка;вернуть {. , , государство,character_edit_form_data: {. , , государство. character_edit_form_data,[персонаж. Я бы]: {. , , form_data}}}дело FlixActions. полезная нагрузка. персонаж;const edit_form_data = состояние. character_edit_form_data [характер. Я бы];const characters = state. персонажи. map (char => {if (знак id === знак. id) возврат {. , , char, имя: edit_form_data. имя, описание: edit_form_data. описание}return char;});вернуть {. , , государство,персонажи,show_character_edit: {. , , государство. show_character_edit,[персонаж. id]: false}}// .}}    
  // GotCharacters. JSexport const CharacterRow = ({character, character_show_description, character_edit_form_data, show_character_edit, toggleCharacterDescription, toggleEdit, syncCharacterEditData, editCharacterDetails}) => {const toggleEditPartial = toggleEdit. bind (null, character);return (
{character. имя}
{Character_show_description [характер. Я бы] ? 'collapse': 'expand'}{! Character_show_description [характер. id] && редактировать}{Character_show_description [характер. Я бы] &&
{character. описание}
}{Show_character_edit [характер. Я бы] &&}
);}export const РедактироватьCharacterDetails = ({character, edit_data, syncCharacterEditData, editCharacterDetails, cancelEdit}) => {const syncFormData = (ключ, e) => {const {значение} = e. currentTarget;syncCharacterEditData (символ, {.edit_data,[ключ]: значение});};const saveForm = (e) => {е. preventDefault ;editCharacterDetails (символ);};вернуть (
March 1, 2018