在React中切换嵌套状态对象

时间:2019-01-22 20:29:15

标签: javascript reactjs react-state-management

我有一个包含对象数组的状态对象:

this.state = {
  feeling: [
    { name: 'alert', status: false },
    { name: 'calm', status: false },
    { name: 'creative', status: false },
    { name: 'productive', status: false },
    { name: 'relaxed', status: false },
    { name: 'sleepy', status: false },
    { name: 'uplifted', status: false }
  ]
}

我希望在单击事件时将布尔值status从true切换为false。我将此函数构建为单击处理程序,但未将事件连接到状态更改中:

buttonToggle = (event) => {
  event.persist();
  const value = !event.target.value

  this.setState( prevState => ({
    status: !prevState.status
  }))
}

我很难跟踪嵌套的React状态更改的控制流程,以及活动事件如何使从处理程序跳转到状态对象,反之亦然。

整个组件:

export default class StatePractice extends React.Component {

  constructor() {
    super();
    this.state = {
      feeling: [
        { name: 'alert', status: false },
        { name: 'calm', status: false },
        { name: 'creative', status: false },
        { name: 'productive', status: false },
        { name: 'relaxed', status: false },
        { name: 'sleepy', status: false },
        { name: 'uplifted', status: false }
      ]
    }
  }

  buttonToggle = (event) => {
    event.persist();
    const value = !event.target.value

    this.setState( prevState => ({
      status: !prevState.status
    }))
  }



  render() {
    return (  
      <div>
        { this.state.feeling.map(
            (stateObj, index) => { 
              return <button 
                key={ index }
                onClick={ this.buttonToggle } 
                value={ stateObj.status } >
                  { stateObj.status.toString() }
                </button>
            }
          )
        }
      </div>
    )
  }
}  

3 个答案:

答案 0 :(得分:1)

在反应状态对象中更新嵌套对象非常棘手。您必须从状态中的临时变量中获取整个对象,更新该变量中的值,然后用更新后的变量替换状态。 为此,您的buttonToggle函数需要知道按下了哪个按钮。

return <button 
  key={ index }
  onClick={ (event) => this.buttonToggle(event, stateObj.name) } 
  value={ stateObj.status } >
    { stateObj.status.toString() }
  </button>

您的buttonToggle函数可能如下所示

buttonToggle = (event, name) => {
  event.persist();

  let { feeling } = this.state;
    let newFeeling = [];

  for (let index in feeling) {
    let feel = feeling[index];
    if (feel.name == name) {
        feel = {name: feel.name, status: !feel.status};
    }
    newFeeling.push(feel);
  }

  this.setState({
    feeling: newFeeling,
  });
}

Here's工作的JSFiddle。

或者,如果您不需要为每种感觉存储比“名称”和“状态”更多的数据,则可以这样重写组件状态:

 feeling: {
    alert: false,
    calm: false,
    creative: false,
    etc...
  }

和buttonToggle:

 buttonToggle = (event, name) => {
   event.persist();
   let { feeling } = this.state;
   feeling[name] = !feeling[name];
   this.setState({
    feeling
   });
 }

答案 1 :(得分:0)

为了解决您的问题,您应该首先将要修改的元素的索引发送到切换功能:

onClick = {this.buttonToggle(index)} 

然后调整该函数以同时接收索引和事件。

现在,要修改状态数组,将其复制,更改所需的值,然后将其放回状态:

buttonToggle = index => event => {
    event.persist();
    const feeling = [...this.state.feeling]; //Copy your array
    feeling[index] = !feeling[index];
    this.setState({ feeling }); 
}

您还可以使用slice复制数组,甚至直接发送仅更改一个值的mapped数组。

答案 2 :(得分:0)

我认为您在获取事件时需要更新整个数组。并且最好不要改变现有状态。我会推荐以下代码

export default class StatePractice extends React.Component {
  constructor() {
    super();
    this.state = {
      feeling: [
        { name: "alert", status: false },
        { name: "calm", status: false },
        { name: "creative", status: false },
        { name: "productive", status: false },
        { name: "relaxed", status: false },
        { name: "sleepy", status: false },
        { name: "uplifted", status: false },
      ],
    };
  }

  buttonToggle = (index, value) => (event) => {
    event.persist();
    const toUpdate = { ...this.state.feeling[index], status: !value };
    const feeling = [...this.state.feeling];
    feeling.splice(index, 1, toUpdate);
    this.setState({
      feeling,
    });
  };

  render() {
    return (
      <div>
        {this.state.feeling.map((stateObj, index) => {
          return (
            <button
              key={index}
              onClick={this.buttonToggle(index, stateObj.status)}
              value={stateObj.status}
            >
              {stateObj.status.toString()}
            </button>
          );
        })}
      </div>
    );
  }
}