我有一个用例,我有一个容器,比如说BarChartContainer。此容器将URL作为prop,并且在此URL的基础上,我的saga获取所需的数据,并将其发送到BarChartComponent(PureComponent),该BarChartComponent从此BarChartContainer调用以呈现条形图。 现在,我希望这是动态的,如果我想在3个地方的容器中使用它,我只需要传递所需URL的支柱,并且容器的每个实例都应该根据URL呈现数据。我面临的问题是,尽管每次调用此容器都有不同的道具,但容器只有一个商店。所以最终,只有1个URL存储在商店中(即来自BarChartContainer第三个实例的道具的URL。我应该如何配置商店,以便它维护树,以保持实例的状态。
这是我的容器的代码
export class BarChartContainer extends React.PureComponent {
static propTypes = {
initializeBarChart: PropTypes.func,
data: PropTypes.object.isRequired,
dataUrl: PropTypes.string,
addUrlToStore: PropTypes.func,
};
/**
*Defines the default values of certain props
*
* @static
* @memberof BarChartContainer
*/
static defaultProps = {
data: {},
dataUrl: '',
};
/**
*This function is called on the initial load of BarChartContainer
*
* @memberof BarChartContainer
*/
componentWillMount() {
this.props.addUrlToStore(this.props.dataUrl);
this.props.initializeBarChart();
}
render() {
return (
<div className="container-barchartcontainer">
<BarChart data={this.props.data.dataPoints} />
</div>
);
}
}
const mapStateToProps = createStructuredSelector({
data: selectData(),
});
function mapDispatchToProps(dispatch) {
return {
initializeBarChart: () => dispatch(defaultAction()),
addUrlToStore: (url) => dispatch(addUrlToStoreAction(url)),
};
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'barChartContainer', reducer });
const withSaga = injectSaga({ key: 'barChartContainer`, saga });
export default compose(
withReducer,
withSaga,
withConnect,
)(BarChartContainer);
这里是三个容器的持有者
export default class Holder extends React.PureComponent {
render() {
return (
<div className="container-holder">
<BarChartContainer dataUrl='url1' />
<BarChartContainer dataUrl='url2' />
<BarChartContainer dataUrl='url3' />
</div>
);
}
}
答案 0 :(得分:0)
为了达到你想要的效果,(IMO)你必须重新思考模型/过程。
与商店绑定的容器不可重复使用,如果它们代表商店的不同部分,它们不应该是。在这种情况下,因为数据是不同的声音,因为它们实际上代表了商店的不同部分。所以可重用的部分只是渲染部分,但没有别的。
如果是这种情况,那么(IMO)我会为我需要表示的商店的每个部分创建一个容器,我也会创建用于呈现数据的组件。
由于每个图形代表语义上不同的东西,因此在简单性和可伸缩性方面分别获得它们。
另一点是,由于数据来自不同的来源,每个容器可能需要不同的方式来处理和管理与其各自来源的通信(例外,身份验证,授权等)。
在你的情况下,我会创建三个主要容器和一个BarChartContainer:
// If this URL is likely going to be hardcoded, then It does not make any sense to be passed as a prop.
// If this URL comes from a dynamic source, then it should have already been injected to the store when the URL was got
const dataUrl = 'http://url.com';
class ParticularBussinessBarChart extends React.Component {
componentWillMount() {
this.props.addUrlToStore(dataUrl); //This could not make sense
this.props.initializeParticularBussinessBarChart(); // Why not injecting the url here directly?
}
render() {
return (
<BarChartContainer dataPoints={this.props.data.dataPoints} />
);
}
}
const mapStateToProps = createStructuredSelector({
data: selectData(),
});
function mapDispatchToProps(dispatch) {
return {
initializeParticularBussinessBarChart: () => dispatch(defaultAction()),
addUrlToStore: (url) => dispatch(addUrlToStoreAction(url)),
};
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'particularBussinessBarChart', reducer });
const withSaga = injectSaga({ key: 'particularBussinessBarChart`, saga });
export default compose(
withReducer,
withSaga,
withConnect,
)(ParticularBussinessBarChart);
然后我会有一个可重用的组件来负责渲染图形,但没有别的。
//This class might become useless with this workaround
export class BarChartContainer extends React.PureComponent {
render() {
return (
<div className="container-barchartcontainer">
<BarChart data={this.props.dataPoints} />
</div>
);
}
}
用法是:
export default class Holder extends React.Component {
componentWillMount() {
this.props.addUrlToStore(dataUrl); //This could not make sense
this.props.initializeParticularBussinessBarChart(); // Why not injecting the url here directly?
}
render() {
return (
<div className="container-holder">
<ParticularBussinessBarChart/>
<OtherParticularBussinessBarChart />
<AnotherParticularBussinessBarChart />
</div>
);
}
}
另一个选择是让一个Holder负责获取并分别将相应的数据传递给每个图表。 这个选项在开始时会更简单,但如果添加更多图表,可能会变得更加复杂。
export class BarChartContainer extends React.PureComponent {
render() {
return (
<div className="container-barchartcontainer">
<BarChart data={this.props.dataPoints} />
</div>
);
}
}
用法是:
class Holder extends React.Component {
componentWillMount() {
this.props.initializeBarChart1('url1');
this.props.initializeBarChart2('url2');
this.props.initializeBarChart3('url3');
}
render() {
return (
<div className="container-holder">
<BarChartContainer dataPoints={this.props.dataPointsChart1} />
<BarChartContainer dataPoints={this.props.dataPointsChart2} />
<BarChartContainer dataPoints={this.props.dataPointsChart3} />
</div>
);
}
}
const mapStateToProps = createStructuredSelector({
dataPointsChart1: selectDataForChar1(),
dataPointsChart2: selectDataForChar2(),
dataPointsChart3: selectDataForChar3(),
});
function mapDispatchToProps(dispatch) {
return {
initializeBarChart1: () => dispatch(correspondingAction()),
initializeBarChart2: () => dispatch(correspondingAction()),
initializeBarChart3: () => dispatch(correspondingAction()),
};
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'holder', reducer });
const withSaga = injectSaga({ key: 'holder`, saga });
export default compose(
withReducer,
withSaga,
withConnect,
)(ParticularBussinessBarChart);
我更愿意选择第一个选项,因为它似乎对我来说更具可扩展性和简单性。但这实际上取决于你提供的图表的业务和性质。