Подтвердить что ты не робот

Как обрабатывать глобальные данные состояния в глубоко вложенных компонентах в Redux?

Итак, скажите, что у вас есть приложение чата с этой составной структурой:

<ChatApp>
  <CurrentUserInfo>...</CurrentUserInfo>
  <ChatsPanel>...</ChatsPanel>
  <SelectedChatPanel>
    <MessagesList>
      <MessageBaloon>
        <MessageText></MessageText>
        <MessageUserHead></MessageUserHead>
      </MessageBaloon>
      ...
    </MessagesList>
  <SelectedChatPanel>
</ChatApp>

И состояние Redux вроде:

{ 
  currentUser: ...,
  chatsList: ...,
  selectedChatIndex: ...,
  messagesList: [ ... ]
}

Как вы можете сделать текущую информацию пользователя доступной к компоненту <MessageUserHead> (который будет отображать текущую миниатюру пользователя для каждого сообщения) без необходимости передавать ее полностью из корневого компонента через все промежуточные компоненты?

Точно так же, как вы могли бы предоставлять информацию, такую ​​как текущий язык, тему и т.д. для каждого презентационного/немого компонента в дереве компонентов, не прибегая к раскрытию всего объекта состояния?

4b9b3361

Ответ 1

Для информации, которая является глобальной для всех ваших "немых" компонентов, вы можете использовать реагировать на контексты.

Надуманный пример

// redux aware component
var ChatApp = React.createClass({
  childContextTypes: {
    language: React.PropTypes.string
  },
  getChildContext: function() {
    // or pull from your state tree
    return {language: "en"};
  },
  ...
}

// dumb components
var ExDumb = React.createClass({
  contextTypes: {
    language: React.PropTypes.string
  },

  render: function() {
    var lang = this.context.language;
    return ( <div /> );
   }
 });

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

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

Ответ 2

(ОБНОВЛЕНИЕ: потратив некоторое время на вариант 4, я лично считаю, что это путь. Я опубликовал библиотеку react-redux-controller, построенную на этом подходе. )

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

Цепочка реквизитов

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

Селекторы во всех компонентах

В качестве альтернативы вы можете использовать connect, чтобы сделать доступными данные из вашего хранилища Redux, независимо от того, где вы находитесь в дереве компонентов. Это отделяет ваши компоненты друг от друга, но он соединяет все с Redux. Я хотел бы отметить, что принципиальный автор Redux не обязательно против этого подхода. И это, вероятно, более результативно, так как это предотвращает повторную визуализацию промежуточных компонентов из-за изменений в props, на которые они действительно не заботятся.

Реакция children

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

Реагировать на контекст

Как уже упоминалось @mattclemens, вы можете использовать экспериментальный контекст api, чтобы разделить ваши промежуточные компоненты. Да, это "экспериментальный". Да, команда React определенно, похоже, не влюблена в нее. Но имейте в виду, что это именно то, что Redux connect использует для ввода dispatch и реквизита из селекторов.

Я думаю, что он поражает хороший баланс. Компоненты остаются развязанными, потому что компонентам ветки не нужно заботиться о зависимостях потомков. Если вы используете только connect в корневом каталоге, чтобы настроить контекст, то всем потомкам нужно только связать контекстный API React, а не Redux. Компоненты могут быть свободно переупорядочены, если какой-то предок устанавливает требуемые свойства context. Если единственным компонентом, который устанавливает context, является корневая компонента, это тривиально верно.

Команда React сравнивает использование context с глобальными переменными, но это кажется преувеличением. Мне кажется, это больше похоже на инъекцию зависимостей.