首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将嵌套对象/数组变异为React中的状态

将嵌套对象/数组变异为React中的状态
EN

Stack Overflow用户
提问于 2018-10-15 04:05:45
回答 2查看 1.9K关注 0票数 -2

我使用的React组件看起来像这样(下面是我使用的组件的简化版本)。

我的问题是:如何在使用this.setState的情况下实现同样的效果?下面的代码可以工作,但我直接改变了状态,并收到以下警告:

不会直接改变状态。使用setState()

代码语言:javascript
复制
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      playerState: [
        {
          name: 'Jack',
          hp: 30
        },{
          name: 'Alan',
          hp: 28
        }
      ],
    };
  }
  lowerPlayerHealth = (index) => () => {
    this.state.playerState[index].hp = this.state.playerState[index].hp - 1
    this.forceUpdate();
  }
  render() {
    return (
      <div className="App">
        <p>Player 1: {this.state.playerState[0].name}</p>
        <p>Health: {this.state.playerState[0].hp}</p>
        <button onClick={this.lowerPlayerHealth(0)}>Hit player 1</button>
        <p>Player 2: {this.state.playerState[1].name}</p>
        <p>Health: {this.state.playerState[1].hp}</p>
        <button onClick={this.lowerPlayerHealth(1)}>Hit player 2</button>
      </div>
    );
  }
}

渲染时,它看起来如下所示:

EN

回答 2

Stack Overflow用户

发布于 2018-10-15 05:35:50

如果要修改状态中的现有值,则永远不应直接从状态获取值并更新状态对象,而应使用setState中的updater函数,以便确保状态值是更新状态时所需的状态值。这就是React的状态是如何工作的,这是一个非常常见的React错误。

official docs

setState()并不总是立即更新组件。它可能会批量或将更新推迟到以后。这使得在调用setState()之后立即读取this.state成为一个潜在的陷阱。相反,可以使用componentDidUpdate或setState回调(setState(updater,callback)),这两个回调都保证在应用更新后触发。如果您需要根据之前的状态设置状态,请阅读下面的更新程序参数。

除非shouldComponentUpdate()返回false,否则setState()总是会导致重新呈现。如果正在使用可变对象,并且无法在shouldComponentUpdate()中实现条件呈现逻辑,则仅在新状态与以前的状态不同时调用setState()可避免不必要的重新呈现。

第一个参数是一个带有签名的更新函数:

(state, props) => stateChange

状态是对应用更改时的组件状态的引用。它不应该被直接变异。相反,应该通过基于state和props的输入构建一个新对象来表示更改。

由更新器函数接收的状态和属性都保证是最新的。更新器的输出与状态进行了简单的合并。

因此,当您想要使用更新程序函数的第一个参数更新setState函数中的组件时,必须准确地获取该值。

代码语言:javascript
复制
lowerPlayerHealth = (index) => () => {
    // use setState rather than mutating the state directly
    this.setState((state, props) => {
    // state here is the current state. Use it to update the current value found in state and ensure that it will be set correctly
      return (state); // update state ensuring the correct values
    });
  }

解决方案

要降低状态中找到的值,请执行以下操作:

代码语言:javascript
复制
class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      playerState: [
        {
          name: 'Jack',
          hp: 30
        }, {
          name: 'Alan',
          hp: 28
        }
      ],
      };
  }

  lowerPlayerHealth = (index) => () => {
    this.setState((state, props) => {
      state.playerState[index].hp -=1; //update the current value found in state
      return (state); // update state ensuring the correct values
    });
  }

  render() {
    return (
      <div className="App">
        <p>Player 1: {this.state.playerState[0].name}</p>
        <p>Health: {this.state.playerState[0].hp}</p>
        <button onClick={this.lowerPlayerHealth(0)}>Hit player 1</button>
        <p>Player 2: {this.state.playerState[1].name}</p>
        <p>Health: {this.state.playerState[1].hp}</p>
        <button onClick={this.lowerPlayerHealth(1)}>Hit player 2</button>
      </div>
      );
  }
}
票数 2
EN

Stack Overflow用户

发布于 2018-10-15 04:12:46

你已经回答了你自己的问题:不要改变状态。此外,最佳实践建议使用setState的函数版本。

因为playerState是一个数组,所以使用Array.map to create a new array containing the same objects,只替换您想要更改的那个:

代码语言:javascript
复制
lowerPlayerHealth = (indexToUpdate) => () => {
  this.setState(state => ({
    ...state,
    playerState: state.playerState.map(
      (item, index) => index === indexToUpdate
        ? {
          ...item,
          hp: item.hp - 1
        }
        : oldItem
    )
  }));
}

如果将playerState设置为对象而不是数组,则可以使其更整洁:

代码语言:javascript
复制
lowerPlayerHealth = (indexToUpdate) => () => {
  this.setState(state => ({
    ...state,
    playerState: {
      ...state.playerState,
      [indexToUpdate]: {
        ...state.playerState[indexToUpdate],
        hp: state.playerState[idToindexToUpdatepdate].hp - 1
      }
    }
  }));
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52806627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档