1

我想用反应显示一个可选择的对象列表。我有列表组件,它拥有几个组,这些组拥有几个元素。显然,列表数据本身应该进入存储,但是 UI 状态(例如,选择了哪个元素)呢?它表面上是根列表元素的一个属性,但要将其传递给元素,链上的每个元素(好吧,在这种情况下只有 1 个 - 组)都需要传递它,即使他们不关心它。如果我想添加另一个属性,我需要相当冗长地将它传递到链中。

还有,封装。如何制作一个可能使用不同数据多次实例化的组件?

在其他语言中,我只会将列表指针传递到链中,以便子元素可以从中获得任何他们想要的东西,所以一切都保持封装。通量方式是将商店传递给子元素吗?你会为 UI 状态和持久数据单独存储吗?

4

1 回答 1

2

让我们从下往上设计。所以,在底部我们有一个 ListItem。

列表项需要什么才能呈现?假设它是一个标题、一个正文,以及它是否被选中。

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

它有任何状态吗?不,除非我们需要处理诸如悬停或其他特定于 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 不太明显。

对于 props,我们将要求提供一个项目列表、选定的索引(如果有的话)和一个 onSelectionChange 回调,它被调用(nextIndex, lastIndex)

该组件也没有状态。对于额外的点,我们将允许指定自定义渲染器,使其更可重用。您可以传递renderer={component}where 组件是实现上述 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被选中,否则它不是。

于 2015-01-16T07:42:34.913 回答