如何在子组件之间管理UI状态?

时间:2015-01-16 01:07:55

标签: reactjs reactjs-flux

我想显示一个带有反应的可选对象列表。我有列表组件,它拥有几个组,它们拥有多个元素。显然,列表数据本身应该进入商店,但是UI状态如何(例如,选择了哪个元素)?它是根列表元素的一个属性,但要将其传递给元素,沿着链的每个元素(在这种情况下只有1个 - 组)将需要传递它,即使它们不关心它。如果我想添加另一个属性,我需要将其传递给链,而不是冗长。

另外,封装。如何使用不同的数据创建可能多次实例化的组件?

在其他语言中,我只是将列表指针传递给链,这样子元素就可以随心所欲,所以一切都保持封装状态。通量方式是将商店传递给子元素吗?你是否有一个单独的UI状态存储与持久数据存储?

1 个答案:

答案 0 :(得分:2)

让我们自下而上地设计这个。所以,在底部我们有一个ListItem。

列表项需要什么才能呈现?让我们说它是一个标题,一个正文,如果它被选中或不被选中。

哪些事件对列表项有意义?可能只是onClick。

它有任何州吗?不,除非我们需要处理它被悬停的事情,或者特定于ListItem的其他状态,但与其父项无关。

var ListItem = React.createClass({
  render(){
    var classNames = ["list-item"];

    if (this.props.selected) classNames.push("selected");

    return (
      <li className={classNames.join} onClick={this.props.onClick}>
        <div className="title">{this.props.title}</div>
        <div className="body">{this.props.body}</div>
      </li>
    );
  }
});

ListGroup有点不太明显。

对于道具,我们会要求提供项目列表,所选索引(如果有)以及使用(nextIndex, lastIndex)调用的onSelectionChange回调。

此组件也没有状态。对于额外的点,我们将允许指定自定义渲染器,使其更可重用。您可以传递renderer={component},其中component是实现上述ListItem接口的东西。

var ListGroup = React.createClass({
  getDefaultProps: function(){
    return {renderer: ListItem, onSelectionChange: function(){}}
  },
  render(){
    return (
      <div>{this.props.items.map(this.renderItem)}</div>
    );  
  },
  renderItem(data, index){
    var selectedIndex = this.props.selectedIndex;
    return (
      <this.props.renderer 
        selected={selectedIndex === index}
        key={i}
        onClick={() => this.props.onSelectionChange(index, selectedIndex)}
        {...data} />
  }
});

然后我们可以像这样呈现ListGroup:

<ListGroup 
  items={[{title: "foo", body: "bar"}, {title: "baz", body: "quux"]}
  selectedIndex={this.state.i}
  onSelectionChange={(index) => this.setState({i: index})} />

数据在树下传递,但只传递呈现每个组件所需的数据的本质。 ListItem不需要完整的项目列表,也不需要选定的索引。它不关心是允许多个选择,还是只允许一个选择。它只知道当this.props.selected真实时它被选中,否则就不是。

相关问题