我正在研究一个包含许多子组件的组件,其中一些子组件嵌套了五个子组件。我有兴趣使用redux来获得在共同状态原子中具有单一真实来源的优势。
我不理解的是智能/愚蠢的组件推荐,并将提供者置于主要组件之上,并通过道具传递所有内容。如果我这样做,那么我需要将道具一直传递到第五个嵌套项目,这样它就可以进行回调以调度一个动作或查看只有它需要的状态,而不是它的父项。我理解这是用于代码重用,但子组件永远不会在主组件之外使用。这里推荐的解决方案是什么?仍然使用道具?
注意:此库的作者要求我们在StackOverflow上提问。我之所以提到这一点,是因为SO似乎将“最佳实践”问题标记得太模糊了。
答案 0 :(得分:9)
虽然发布的answer亚光克拉门斯确实涵盖了这一点,但我会在这里尝试更深入。
您可以在任何级别使用connect()
。这样做会使组件智能,因为它知道props
的来源。 dumb 组件只有props
,它们可以来自任何地方。智能组件耦合到redux;一个愚蠢的组成部分不是。
There are differing opinions on this approach,但支持且有效。
绘制此行的位置完全取决于您,但让我们看一个示例。您有一些聊天客户端,其标准侧边栏组件,消息窗口和用于发送新消息的输入字段。
+---------+--------------------------+
| | |
|Sidebar | Messages window |
| | |
| | |
| | |
| | |
| +--------------------------+
| | New Message Entry **|
| | |
+---------+--------------------------+
所有这些的父级将使用connect()
从redux获取数据并通过props将其提供给这些组件。现在想象除new message entry
之外的那两个星号打开一个设置面板(忽略愚蠢的位置,这是一个例子)。 new message entry
通过这些道具真的有意义吗?不,它没有。
要解决此问题,您可以创建一个特殊的"容器",让我们调用它SettingsContainer
使用connect()
来获取它的道具,它所做的只是将它们传递给{{ 1}}。 SettingsPopup
不会知道redux,并且仍然可以正常测试/样式化/重用,而新的消息条目只需要知道SettingsPopup
,而不是任何依赖。
这种方法可以很好地扩展,但它有两个惩罚。首先,智能包装"像SettingsContainer
这样的组件必须由其他哑组件使用。这使新消息条目组件的测试变得复杂。其次,顶级组件不再公开数据依赖关系的整个图形,这使得在不深入研究组件层次结构的情况下更难以推理。
这些权衡可能是值得的,但你应该知道它们。
答案 1 :(得分:5)
您可以使用' react-redux'的组件context来使用Provider的新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')
);
答案 2 :(得分:3)
更新:如果您想尝试以下方法,请查看我最近发布的https://github.com/artsy/react-redux-controller。
我认为最好的方法是将选择器映射到根(容器)组件的data=
cube(
array[cube_ll_coord(a.data, 1), cube_ll_coord(a.data, 2),
cube_ll_coord(a.data, 3), cube_ll_coord(a.data, 4)],
array[cube_ur_coord(a.data, 1), cube_ur_coord(a.data, 1),
cube_ur_coord(a.data, 3), cube_ur_coord(b.data, 4)]
)
,而不是拥有一堆容器或在任何地方使用context
。我在自己的项目中做到了这一点并且工作得非常好。它添加了一个新的模式,用它们产生的connect
注释选择器。这让我使用PropType
来允许所有后代保留与childContextTypes
相同的保护。这比传递传递下来的大型无类型对象Ashley Coolman's approach更有优势。我希望在接下来的几天里有时间将其纳入自己的图书馆并发布。
与此同时,我建议making components smart使用propTypes
自由,而不是Tyrsius's approach创建一大堆容器,但那只是我的意见。