简体   繁体   English

在 React 中切换嵌套状态对象

[英]Toggling nested state object in React

I have a state object that contains an array of objects:我有一个包含对象数组的状态对象:

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 }
  ]
}

I want to toggle the boolean status from true to false on click event.我想在单击事件时将布尔status从 true 切换为 false。 I built this function as a click handler but it doesn't connect the event into the state change:我将此函数构建为单击处理程序,但它不会将事件连接到状态更改:

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

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

I'm having a hard time following the control flow of the nested React state change, and how the active event makes the jump from the handler to the state object and vice versa.我很难遵循嵌套 React 状态更改的控制流,以及活动事件如何从处理程序跳转到状态对象,反之亦然。

The whole component:整个组件:

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>
    )
  }
}  

In order to solve your problem, you should first send the index of the element that is going to be modified to your toggle function :为了解决您的问题,您应该首先将要修改的元素的索引发送到您的切换功能:

onClick = {this.buttonToggle(index)} 

Then tweak the function to receive both the index and the event.然后调整函数以接收索引和事件。

Now, to modify your state array, copy it, change the value you are looking for, and put it back in your state :现在,要修改您的状态数组,请复制它,更改您要查找的值,然后将其放回您的状态:

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

You can also use slice to copy your array, or even directly send a mapped array where only one value is changed.您还可以使用slice来复制您的数组,甚至直接发送一个mapped数组,其中只更改一个值。

Updating a nested object in a react state object is tricky.更新反应状态对象中的嵌套对象很棘手。 You have to get the entire object from the state in a temporary variable, update the value within that variable and then replace the state with the updated variable.您必须从临时变量中的状态中获取整个对象,更新该变量中的值,然后用更新后的变量替换状态。 To do that, your buttonToggle function needs to know which button was pressed.为此,您的 buttonToggle 函数需要知道按下了哪个按钮。

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

And your buttonToggle function could look like this你的 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 a working JSFiddle.这是一个有效的 JSFiddle。

Alternatively, if you don't need to store any more data per feeling than "name" and "status", you could rewrite your component state like this:或者,如果您不需要为每种感觉存储比“名称”和“状态”更多的数据,您可以像这样重写组件状态:

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

And buttonToggle:和按钮切换:

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

I think you need to update the whole array when get the event.我认为您需要在获取事件时更新整个数组。 And it is better to not mutate the existing state.而且最好不要改变现有状态。 I would recommend the following code我会推荐以下代码

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>
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM