使用 Redux 容器组件模式来呈现动态数量的 React 子组件的可靠方法是什么?
What is a robust way of rendering a dynamic quantity of React child components, using the Redux container component pattern?
假设我有一个功能性的 React 演示组件,如下所示:
const Functional = (props) => {
// do some stuff
return (
<div>
// more HTML based on the props
</div>
);
}
Functional.propTypes = {
prop1: React.PropTypes.string.isRequired,
prop2: React.PropTypes.string.isRequired,
// ...
};
如果我使用 Redux 并遵循容器组件模式,那么根据数组中的元素(其中在我的 Redux 状态中)?
例如我的 Redux 状态可能如下所示:
{
functionalItems: [
{
prop1: 'x1',
prop2: 'y1',
// ...
},
{
prop1: 'x2',
prop2: 'y2'
},
// ... more items
],
// ...
}
所以 functionalItems
数组中的每个项目都应该对应一个 <Functional/>
组件,它们都被渲染为彼此相邻。
这是我第二次遇到这个问题,所以我希望它足够普遍,可以有很好的解决方案。
我会 post 我能想出的解决方案(但有不受欢迎的特征)作为这个问题的答案。
解决方案说明
- 创建一个包装器功能表示组件,它接收一个数量和函数来获取
<Functional/>
道具值。
- 创建一个连接到这个新包装器组件的容器组件,并传入数量(基于 Redux 状态)和访问器函数以获取
<Functional/>
道具值。
示例代码
Wrapper.jsx:
const Wrapper = (props) => {
const elements = [];
for (let i = 0; i < props.quantity; i++) {
elements.push(
<Functional prop1={ getPropValue1(i) } prop2={ getPropValue2(i) } ...
key={ ... }/>
);
}
return (
<div>
{ elements }
</div>
);
};
Wrapper.propTypes = {
quantity: React.PropTypes.number.isRequired,
getPropValue1: React.PropTypes.func.isRequired,
getPropValue2: React.PropTypes.func.isRequired,
// ...
};
ContainerComponent.js:
const mapStateToProps = (state) => ({
quantity: state.functionalItems.length,
getPropValue1: (index) => state.functionalItems[index].prop1,
getPropValue2: (index) => state.functionalItems[index].prop2,
// ...
});
const ContainerComponent = connect(mapStateToProps)(Wrapper);
我建议您像这样将整个数组传递给包装器组件:
const mapStateToProps = (state) => ({
items: getFunctionalItems(state),
// ...
});
然后在你的 Wrapper.jsx
中,这样做:
const Wrapper = (props) => {
const elements = props.items.map((item, index) => {
<Functional prop1={ item.prop1 } prop2={ item.prop2 } ...
key={ ... /* you can use index here */ }/>
});
return (
<div>
{ elements }
</div>
);
};
...其中 getFunctionalItems()
是访问器函数,它是从状态访问功能项的规范方法。
这样,您可以处理状态结构的变化,或不同的渲染布局。 (因此更强大(我认为))。而且看起来更像是遵循单一职责原则。
假设我有一个功能性的 React 演示组件,如下所示:
const Functional = (props) => {
// do some stuff
return (
<div>
// more HTML based on the props
</div>
);
}
Functional.propTypes = {
prop1: React.PropTypes.string.isRequired,
prop2: React.PropTypes.string.isRequired,
// ...
};
如果我使用 Redux 并遵循容器组件模式,那么根据数组中的元素(其中在我的 Redux 状态中)?
例如我的 Redux 状态可能如下所示:
{
functionalItems: [
{
prop1: 'x1',
prop2: 'y1',
// ...
},
{
prop1: 'x2',
prop2: 'y2'
},
// ... more items
],
// ...
}
所以 functionalItems
数组中的每个项目都应该对应一个 <Functional/>
组件,它们都被渲染为彼此相邻。
这是我第二次遇到这个问题,所以我希望它足够普遍,可以有很好的解决方案。
我会 post 我能想出的解决方案(但有不受欢迎的特征)作为这个问题的答案。
解决方案说明
- 创建一个包装器功能表示组件,它接收一个数量和函数来获取
<Functional/>
道具值。 - 创建一个连接到这个新包装器组件的容器组件,并传入数量(基于 Redux 状态)和访问器函数以获取
<Functional/>
道具值。
示例代码
Wrapper.jsx:
const Wrapper = (props) => {
const elements = [];
for (let i = 0; i < props.quantity; i++) {
elements.push(
<Functional prop1={ getPropValue1(i) } prop2={ getPropValue2(i) } ...
key={ ... }/>
);
}
return (
<div>
{ elements }
</div>
);
};
Wrapper.propTypes = {
quantity: React.PropTypes.number.isRequired,
getPropValue1: React.PropTypes.func.isRequired,
getPropValue2: React.PropTypes.func.isRequired,
// ...
};
ContainerComponent.js:
const mapStateToProps = (state) => ({
quantity: state.functionalItems.length,
getPropValue1: (index) => state.functionalItems[index].prop1,
getPropValue2: (index) => state.functionalItems[index].prop2,
// ...
});
const ContainerComponent = connect(mapStateToProps)(Wrapper);
我建议您像这样将整个数组传递给包装器组件:
const mapStateToProps = (state) => ({
items: getFunctionalItems(state),
// ...
});
然后在你的 Wrapper.jsx
中,这样做:
const Wrapper = (props) => {
const elements = props.items.map((item, index) => {
<Functional prop1={ item.prop1 } prop2={ item.prop2 } ...
key={ ... /* you can use index here */ }/>
});
return (
<div>
{ elements }
</div>
);
};
...其中 getFunctionalItems()
是访问器函数,它是从状态访问功能项的规范方法。
这样,您可以处理状态结构的变化,或不同的渲染布局。 (因此更强大(我认为))。而且看起来更像是遵循单一职责原则。