【问题标题】:How do I manage UI state among subcomponents?如何管理子组件之间的 UI 状态?
【发布时间】:2015-01-16 01:07:54
【问题描述】:

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

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

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

【问题讨论】:

    标签: reactjs reactjs-flux


    【解决方案1】:

    让我们自下而上地设计它。所以,在底部我们有一个 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},其中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 为真时它被选中,否则它不是。

    【讨论】:

    • 您缺少层次结构的一层 - 一个列表包含多个组,并存储选定的状态
    • 是的,我错过了。我想这对你来说是一个练习:-)
    • 并不是我不愿意这样做,或者对你的回应不感激,但问题是如何最好地在组件与其(大)子级之间进行通信。我想您的答案是通过属性委托任何通信?可能使用spread attributes?
    • 是的,但我只在此处使用了 spread 来不对数据格式做出假设,因为我们也不假设 ListGroup 将呈现什么组件,这使得 ListGroup 更加通用。当你想要高度可重用的组件时:使用 props,当你想要在应用程序中重用时:使用 props/event-emitters/stores,当你想要一次性使用时,使用任何东西。
    猜你喜欢
    • 1970-01-01
    • 2019-07-29
    • 2017-09-16
    • 1970-01-01
    • 2016-01-25
    • 2021-01-28
    • 2022-10-24
    • 2021-02-17
    • 2016-08-12
    相关资源
    最近更新 更多