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

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

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

И состояние Redux, например:

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

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

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


person Dema    schedule 15.12.2015    source источник
comment
github.com/vasanthk/react-bits/ blob/master/patterns/ хорошая статья на эту тему   -  person zloctb    schedule 11.01.2018


Ответы (2)


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

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

// 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 использует этот контекстный подход. в своей библиотеке react-redux.

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

person enjoylife    schedule 16.12.2015
comment
Да, я знал о контексте React, но у меня есть две проблемы с этим: во-первых, контекстный API React является экспериментальным, они могут удалить его или значительно изменить. Во-вторых, мой вопрос касался способа решения Redux, независимо от базовой реализации (React, AngularJS и т. д.). - person Dema; 16.12.2015
comment
@Dema, я пытался немного ответить в своем ответе. Но я бы сказал, не бойтесь изменений в context. Это настолько простой API, что маловероятно, что он может измениться каким-либо фундаментальным образом, и он уже стал довольно важным для базовой функциональности библиотек React, таких как react-redux. Сам Redux не дает ответа на ваш вопрос, так как он вообще не связан с концепцией иерархии компонентов. Вы либо используете привязки, такие как react-redux, либо приносите свою сантехнику :) - person acjay; 16.12.2015
comment
Проблема с этим подходом заключается в том, что к компонентам больше нельзя обращаться с помощью свойств. - person jujule; 16.01.2016
comment
@jujule Не могли бы вы уточнить? Что вы имеете в виду под адресованным? - person acjay; 05.02.2016
comment
Да, прости; я имел в виду, что вы больше не можете делать <ExDumb language="fr"/>, и ваш компонент теперь работает только тогда, когда существует контекст, который нарушает возможность повторного использования? Может быть, какой-то HoC мог бы помочь сделать компонент многоразовым, передав контекст реквизитам... - person jujule; 06.02.2016
comment
Мы не должны использовать контекст в компонентах, используя избыточность stackoverflow.com/a/36431583/1429097 - person Abhinav Singi; 26.04.2016
comment
@AbhinavSingi, возможно, избегайте, но когда вы работаете со многими вложенными компонентами в больших приложениях, полезно сократить код, возникающий из-за использования контекста. Тем не менее, важно документировать предположения компонентов при использовании контекста. - person enjoylife; 26.04.2016

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

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

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

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

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

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

Реакция children

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

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

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

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

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

person acjay    schedule 16.12.2015
comment
Обновление: контекст React был задокументирован более подробно — теперь, когда он был принят различными библиотеками. facebook.github.io/react/docs/context.html - person vasa; 18.06.2016
comment
@vasa Я не думаю, что эта страница существенно изменилась с тех пор, как я изначально написал свой ответ. Ходили слухи, что контекстный API может претерпеть значительные изменения, но я не знаю, правда ли это. - person acjay; 18.06.2016