如何在 Redux 中将全局状态数据处理成深度嵌套的组件?

IT技术 javascript reactjs flux redux
2021-05-01 09:09:39

假设您有一个具有以下组件结构的聊天应用程序:

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

还有一个 Redux 状态,如:

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

您如何使当前用户信息可用于<MessageUserHead>组件(将呈现每条消息的当前用户缩略图),而不必从根组件一直传递到所有中间组件?

同样,如何在不暴露整个状态对象的情况下,使组件树中的每个表示/哑组件都可以使用当前语言、主题等信息?

2个回答

(更新:在选项 4 上花了一些时间,我个人认为这是要走的路。我发布了一个库,react-redux-controller围绕这种方法构建。)

我知道有几种方法可以从根组件获取数据,一直到叶组件,再到中间的分支。

props链

Redux 文档,在使用react-redux的上下文中建议通过props. 我不赞成这个想法,因为它将所有中间分支组件与当今的应用程序结构相结合。从好的方面来说,您的 React 代码将相当纯净,并且仅在顶层与 Redux 本身耦合。

所有组件中的选择器

或者,connect无论您在组件树中的哪个位置,您都可以使用Redux 存储中的数据。这将您的组件彼此分离,但它将所有内容都耦合到 Redux。我要指出的是,Redux 的主要作者不一定反对这种方法。而且它的性能可能更高,因为它可以防止由于中间组件props实际上并不关心的变化而重新渲染它们。

react children

我并没有想太多以这种方式做事,但是您可以在最高级别将整个应用程序结构描述为嵌套组件,将 props 直接传递给远程后代,并children用于在分支级别渲染注入的组件。但是,极端情况下,这会使您的容器组件变得非常复杂,尤其是对于具有不止一种类型的子组件的中间组件。由于这个原因,不确定这是否真的可行。

react上下文

正如@mattclemens 首先提到的,您可以使用实验上下文 api来解耦您的中间组件。是的,这是“实验性的”。是的,React 团队似乎并不喜欢它。但请记住,这正是 Reduxconnect用于dispatch从选择器注入和支持的内容。

我认为它取得了很好的平衡。组件保持解耦,因为分支组件不需要关心后代的依赖关系。如果只connect在根使用设置上下文,那么所有后代只需要耦合到 React 的上下文 API,而不是 Redux。组件可以自由地重新排列,只要某些祖先正在设置所需的context属性。如果设置的唯一组件context是根组件,则这是微不足道的。

React 团队将 usingcontext与全局变量进行了比较,但这感觉有点夸张。对我来说,这似乎更像是依赖注入。

对于所有“哑”组件的全局信息,您可以使用react contexts

一个人为的例子

// 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 库中使用了这种上下文方法

更抽象地说,为了在 React 之外使用,您可以在状态树上使用某种 pluck 或选择器函数,并仅返回哑组件所需的全局状态的子集。