【问题标题】:Update State of a Single React Child Component in an Array of Components?更新组件数组中单个 React 子组件的状态?
【发布时间】:2017-05-03 10:38:03
【问题描述】:

到目前为止,当单击展开/折叠所有按钮时,我具有展开/折叠所有功能以显示/隐藏标题组件。

Container 组件是最外层的组件,它保持 openAll 状态,作为 props 向下传递给 Text 组件。

如您所见,在 Container 组件的 render 方法中,我返回了一个嵌套有 Button 组件的 div 和一个标题数组(这是一个嵌套有 Toggle 和 Title 组件的 div)。

我最大的问题是点击Toggle组件时如何设置单个Title组件的状态? Title 和 Toggle 组件都在同一级别上。我尝试使用来自父级(容器组件)的回调,但它对我不起作用。

如果您查看容器内的 onToggle 方法,我将代码注释掉,因为这将一次显示/隐藏所有 Title 组件,而不是单个...这是因为它位于数组中。

Title 组件具有 isOpen 状态,当组件接收到下一个 props 时,它正在由父级的 props(Container 组件 - openAll)设置。

也许是我想多了,做的比看起来的要努力。

初始应用组件:

class App extends React.Component {
  render() {
    return (
      <div>
        <Container text="Text" />
      </div>
    );
  }
}

容器组件:

class Container extends React.Component {
  constructor() {
    super();
    this.state = {
      openAll: true,
    };
    this.onExpandAll = this.onExpandAll.bind(this);
    this.onToggle = this.onToggle.bind(this);
  }
  render(){
    const titles = [];
    for(let i = 0; i < 3; i++){
      titles.push(
        <div key={i}>
          <Toggle text="Toggle" onToggle={this.onToggle} />
          <Title
            onToggle={this.onToggle}
            openAll={this.state.openAll}
            text={this.props.text + ' ' + i} />
        </div>
      );
    }
    return (
      <div>
        <Button text="Expand All" onExpandAll={() => this.onExpandAll(true)}  />
        <Button text="Collapse All" onExpandAll={() => this.onExpandAll(false)} />
        {titles}
      </div>
    );
  }

  onToggle() {
    //this.setState({
      //openAll: true
    //});
  }

  onExpandAll(isAllOpen) {
    this.setState({
      openAll: isAllOpen
    });
  }
}

标题组件:

class Title extends React.Component {
      constructor() {
        super();
        this.state = {
          isOpen: true
        }
      }

      componentWillReceiveProps(nextProps) {
        this.setState({
          isOpen: nextProps.openAll ? true : false
        })
      }

      render(){
        return this.state.isOpen ? <h3 style={{display: "inline-block"}}>{this.props.text}</h3> : null;
      }
    }

切换组件:

class Toggle extends React.Component {
  render(){
    return <button onClick={this.props.onToggle}>{this.props.text}</button>
  }
}

按钮组件:

class Button extends React.Component {
  render(){
    return <button onClick={this.props.onExpandAll}>{this.props.text}</button>
  }
}

HTML 看起来像这样:

Expand All | Collapse All 

Toggle Text 0
Toggle Text 1
Toggle Text 2

感谢您的帮助!

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    我建议添加另一个组件,该组件包含TitleToggle 组件。我们称这个组件为 TitleToggleContainer>

    TitleToggleContainer 将负责 isOpen 的状态,并将有条件地相应地渲染子 Title 组件。

    Toggle 子组件将在componentWillReceiveProps 内将更改的isOpen 状态独立设置为setState,因此只有其兄弟Title 会受到本地更改的影响到isOpen

    修改Container组件:

    class Container extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          openAll: true,
        };
        this.onExpandAll = this.onExpandAll.bind(this);
        this.onToggle = this.onToggle.bind(this);
      }
      render(){
        const titles = [];
        for(let i = 0; i < 3; i++){
          titles.push(
            <TitleToggleContainer 
              key={i}                       // NOTICE how onToggle is no longer passed in,
              isOpen={this.state.openAll}   // ONLY openAll is passed in as a prop `isOpen`
              text={this.props.text + ' ' + i} 
            /> 
          );
        }
        return (
          <div>
            <Button text="Expand All" onExpandAll={() => this.onExpandAll(true)}  />
            <Button text="Collapse All" onExpandAll={() => this.onExpandAll(false)} />
            {titles}
          </div>
        );
      }
    
      onToggle() {
        this.setState({    // this is ok to uncomment, 
          openAll: true    // it won't be used in TitleToggleContainer
        });
      }
    
      onExpandAll(isAllOpen) {
        this.setState({
          openAll: isAllOpen
        });
      }
    }

    新的TitleToggleContainer类:

    class TitleToggleContainer extends React.Component{
      constructor(props){
        super(props);
        this.state = { isOpen: true };
        this.localToggle=::this.localToggle;  // another way to bind a method
      }
      localToggle(){
        this.setState({ isOpen: !this.state.isOpen });
      }
      componentWillReceiveProps(nextProps) {  // you still need this to receive 
        this.setState({                       // prop changes from parent Toggle
          isOpen: nextProps.openAll ? true : false
        });
      }
      render(){
        const titleComponent= this.state.isOpen ? <h3 style={{display: "inline-block"}}>{this.props.text}</h3> : null;
        return (
          <div>
            <Toggle onClick={this.localToggle}/>
            {titleComponent} 
          </div>
        );
      }
    }

    【讨论】:

    • 哇,我觉得自己好笨!我想这就是我正在寻找的答案。我需要离开电脑,因为我整天都在努力解决这个问题。明天早上我会尝试你的解决方案,明天我会给你正确的答案。谢谢你的帮助!我什么时候应该在构造函数和超级中传递道具?大多数时候,我根本不传递道具,因为它仍然有效。
    • 别担心,我希望这对您有所帮助。回复:道具>我已经将道具传递给构造函数,并且超级习惯的力量。仅当您在构造函数中引用要引用 this.props 时才真正需要。
    • 非常感谢!我尝试了你的解决方案,它奏效了。我对他们所有人的本地状态和“全球”状态感到困惑。由于数组,我无法弄清楚如何在单击单个切换按钮时不使“全局”状态影响其中一个。
    • 你一开始就很接近。如果您绘制出应用程序的数据流(数据来自何处、何时/如何更改),它会有所帮助。这样,当您需要重新考虑该功能时,您可以重新访问它。不管怎样,很高兴我能帮上忙
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 2018-10-09
    • 1970-01-01
    • 2018-02-20
    • 2021-04-02
    • 2020-06-05
    • 2019-09-30
    相关资源
    最近更新 更多