Можно ли рассматривать redux как шаблон pub / sub или observer?

#javascript #reactjs #redux

#javascript #reactjs #redux

Вопрос:

Я просто пытаюсь разобраться react.js Тем не менее, я только что закончил несколько учебных пособий в Интернете.

Я совершенно новичок в redux, который является частью некоторых видеоуроков, которые я смотрел. Чем больше я погружаюсь в это, тем меньше для меня смысла в том, что redux заменяет первоначальную идею react.js . В react компонент имеет свое собственное состояние, которое может передаваться через props, чтобы поддерживать рабочий процесс сверху вниз.

С помощью redux мы теперь пытаемся сделать все состояние приложения глобальным, и нам нужно определить действия для управления этим (глобальным) состоянием, так каковы же эти действия, кроме «обычного» шаблона javascript pub / sub или observer? Или, может быть, я ошибаюсь? — Разъяснения будут высоко оценены.

Ответ №1:

Redux не должен «заменять первоначальную идею react.js » думайте об этом скорее как о библиотеке для управления общим состоянием между компонентами и координации изменений состояния. Redux действительно использует шаблон pub / sub, см. Методы хранения здесь: http://redux.js.org/docs/api/Store.html#store-methods Вы найдете subscribe метод, который используется компонентами для подписки на изменения в дереве состояний. Обычно вы не используете store.subscribe напрямую, так как привязки Redux-React ( connect в основном Redux) делают это за вас. Вы можете ознакомиться с фактической реализацией здесь, это не так сложно (на самом деле для меня это главное преимущество Redux по сравнению с другими реализациями Flux): https://github.com/reduxjs/react-redux/blob/4.x/src/components/connect.js#L199

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

Учтите также, что вполне нормально продолжать использовать внутреннее состояние компонентов вместе с Redux. Вы можете использовать внутреннее состояние для сохранения состояния, которое вам не нужно / не хотите делиться с другими компонентами.

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

Действия в Redux по умолчанию являются просто POJO (обычными старыми объектами javascript), вы можете думать о них как о «событиях», которые вы часто отправляете в ответ на действия, инициируемые пользователем (например, пользователь нажал на кнопку), но вы не ограничены этим, вы можете отправлять действие из любого места, где вы хотитехотите. Хранилище Redux прослушивает эти действия и вызывает редукторы (чистые функции), передающие отправленный вами объект action.

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

В этом смысле редуктор — это функция, которая обрабатывает действия и обновляет состояние по мере необходимости.

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

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

С помощью redux-thunk вы можете отправлять функции, а не просто простые объекты. Отправляя функцию, вы эффективно реализуете инверсию шаблона управления очень простым способом. Ваше действие становится «рецептом», описываемым функцией, а не просто простым оператором, как в случае с действием POJO.

Почему только POJOs поддерживается «из коробки», для действий, почему нет базового класса действий или чего-то в этом роде? В основном потому, что в этом нет необходимости. Простой объект (рассматриваемый в основном как пакет для значений) со type свойством — это все, что вам действительно нужно, это, по сути, самый простой из возможных интерфейсов. Вы можете рассматривать это как программирование для интерфейса (действия) вместо реализации.

Почему глобальное состояние лучше, а не каждый компонент управляет своим собственным состоянием? Главным образом потому, что управление состоянием на самом деле является самой сложной частью нетривиального js-приложения. Используя Redux, вы извлекаете всю эту логику из уровня пользовательского интерфейса, что упрощает тестирование. Фактически, в идеале вы должны иметь возможность тестировать всю реальную «бизнес-логику» приложения Redux даже без рендеринга одного компонента.

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

Наличие состояния в виде единого сериализуемого объекта json также упрощает отладку, создание моментального снимка и отправку / восстановление с сервера или локального хранилища.

Комментарии:

1. just POJO (plain old javascript objects) 🙂 Я никогда не сталкивался с этим термином за пределами Java. Я думаю, это работает, но это смутило меня на несколько секунд, когда я прочитал его первым.

2. Да, я не разработчик Java, но я знаю, откуда взялась аббревиатура 🙂

Ответ №2:

Не удается проголосовать за ответ Fabios дважды, а раздел комментариев слишком мал:

Да, на мой взгляд, это похоже на pub / sub с соглашением.

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

Допустим, у вас есть компонент, который отображает текущего зарегистрированного пользователя. Иерархия ваших компонентов похожа на огромное дерево. Теперь, если бы вы отображали этот компонент в ветке, начинающейся с корня, и в другой ветке, также начинающейся с корня, каждый глубоко в иерархии, вам пришлось бы передавать информацию пользователя из корневого компонента в конечные узлы по 2 разным путям, загрязняя реквизиты каждого компонентатаким образом (которые вообще не связаны с информацией пользователя, но теперь им нужно знать).

Комментарии:

1. @vsync Вы неправильно понимаете, как это работает, поскольку предполагаете, что ваш индивидуальный таймер является компонентами с отслеживанием состояния. Их не должно быть: все дело в том, что каждое состояние таймера находится в хранилище, а ваши «таймеры» — это просто визуальные представления каждого из этих подсостояний. Вы все равно отправите RESET_ALL_TIMERS действие, а затем ваш редуктор отреагирует на это событие, прокручивая каждый из таймеров, сбрасывая их. Супер просто и легко тестировать.

2. @oligofren Я не думаю, что он неправильно понимает, как это работает. Он привел прекрасный пример того, как это реализовано в простом React, без Redux, т. Е. Без действий / редукторов. Вы не можете отправить «RESET_ALL_TIMERS» на простой React. Ваш пример является примером Redux, и в этом весь смысл его аргумента (о том, как Redux улучшает разработку React, позволяя отправлять сообщения вместо того, чтобы сильно полагаться на «props»).

3. @DanielLoureiro Я думаю, вы можете неправильно понять, что я комментирую. Я не комментировал ответ Майка, а комментарий @vsync, который с тех пор был удален. Отсюда @vsync 🙂

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

5. О, я понимаю. Извините за недоразумение. Я не заметил, что имена были разными (mike / vsync). Я думал, что вы комментируете ответ Майка, и я запутался. Лол