我应该如何将redux与不会被重用的嵌套子组件一起使用?

Bra*_*ord 13 javascript reactjs redux

我正在研究一个有很多子组件的组件,其中一些子组件嵌套了五个子组件.我有兴趣使用redux来获得在共同状态原子中具有单一真实来源的优势.

我不理解的是智能/愚蠢的组件推荐,并将提供者置于主要组件之上,并通过道具传递所有内容.如果我这样做,那么我需要将道具一直传递到第五个嵌套项目,这样它就可以进行回调以调度一个动作或查看只有它需要的状态,而不是它的父项.我理解这是用于代码重用,但子组件永远不会在主组件之外使用.这里推荐的解决方案是什么?还在用道具?

注意:该库的作者要求我们在StackOverflow上提问.我之所以提到这一点,是因为SO似乎将"最佳实践"问题标记为过于模糊.

Kye*_*ica 10

虽然发布的答案亚光克莱门斯确实涵盖了这个高水平,但我会尝试在这里更深入.

您可以connect()在任何级别使用.这样做会使组件变得聪明,因为它知道它的props来源.一个愚蠢的组件只有props,它们可以来自任何地方.智能组件 redux 耦合 ; 一个愚蠢的组成部分不是.

关于这种方法有不同的意见,但它是受支持和有效的.

在哪里绘制这条线完全取决于你,但让我们看一个例子.您有一些聊天客户端,其标准侧边栏组件,消息窗口和用于发送新消息的输入字段.

+---------+--------------------------+
|         |                          |
|Sidebar  |  Messages window         |
|         |                          |
|         |                          |
|         |                          |
|         |                          |
|         +--------------------------+
|         |  New Message Entry     **|
|         |                          |
+---------+--------------------------+
Run Code Online (Sandbox Code Playgroud)

所有这些的父级将用于connect()从redux获取数据并通过props将其提供给这些组件.现在想象那两个星号除了new message entry打开一个设置面板(忽略愚蠢的位置,这是一个例子).new message entry通过这些道具真的有意义吗?不,它没有.

为了解决这个问题,你可以创建一个特殊的"容器",让我们把它叫做SettingsContainer是用来connect()获取其道具和它所作的只是将它们传递下来SettingsPopup.SettingsPopup不会知道redux,并且仍然可以正常测试/样式化/重用,而新的消息条目只需要知道SettingsContainer,而不是任何依赖.

这种方法可以很好地扩展,但它有两个惩罚.首先,智能"包装"组件SettingsContainer必须由其他愚蠢的组件消耗.这使新消息条目组件的测试变得复杂.其次,顶级组件不再公开数据依赖关系的整个图形,这使得在不深入研究组件层次结构的情况下更难以推理.

这些权衡可能是值得的,但你应该知道它们.


Ash*_*man 5

您可以使用'react-redux'的组件提供程序,使用上下文的较新React功能.使用Provider将抽象出一些上下文的实现细节,使你的标记非常富有表现力.

您基本上设置了一个迷你全局属性,所有子组件,哑或智能可以引用:

import React from 'react';
import {render} from 'react-dom';
import {createStore} from 'redux';
import {Provider} from 'react-redux'; //Special Redux component to help
import {reducers} from './reducers.js';


var DeepDumbChild = (props, context) => (
    <div>
        <pre>
            {JSON.stringify(data, null, 2)}
        </pre>
    </div>
)


class SmartChild extends React.Component {
    render() {
        /* Use the global-like context */
        let data = this.context.store.getState();
        return (
            <div>
                <DeepDumbChild data={data}/>
            </div>
        )
    }
}
SmartChild.contextTypes = {
    store: React.PropsTypes.object /* required */
}

/* No messy props :) */
var App = () => (<div>
    <SmartChild/>
</div>);


render(
    <Provider store={createStore(reducers)}>
        <App/>
    </Provider>,
    document.getElementById('app')
);
Run Code Online (Sandbox Code Playgroud)