reactjs - 如果ReactJS状态具有map属性,则更改map值不会反射(reflect)状态

标签 reactjs setstate

我有一个名为 Counters 的组件

export default class Counters extends Component {
  state = {
    counterMap: {}
  };
  noOfComponents = 5;

  componentWillMount() {
    var counterMap = new Map();
    for (var i = 0; i < this.noOfComponents; i++) {
      var counter = {
        id: i + 1,
        value: i + 1,
        key: i + 1
      };
      counterMap.set(i + 1, counter);
    }
    this.setState({ counterMap });
  }

  handleDecrease = counterId => {
    // This is always Called from the inner child... Verified !
    const { counterMap } = this.state;
    const counter = counterMap.get(counterId);
    counter.value = counter.value - 1;
    counterMap.delete(counterId);
    counterMap.set(counterId, counter);
    this.setState({ counterMap: counterMap });
  };

  render() {
    const counterComps = [];
    this.state.counterMap.forEach(element => {
      const counter = (
        <Counter
          data={element}
          onDecrease={this.handleDecrease}
          onIncrease={this.handleIncrease}
        />
      );
      counterComps.push(counter);
    });
    return <div>{counterComps}</div>;
  }
}

我的问题是

handleDecrease = counterId => {
  // This is always Called
  const { counterMap } = this.state;
  const counter = counterMap.get(counterId);
  counter.value = counter.value - 1;
  counterMap.delete(counterId);
  counterMap.set(counterId, counter);
  this.setState({ counterMap: counterMap });
}

这在用户界面中不起作用。

计数器值的更改不会反射(reflect)在 UI 中。 我的想法是因为 map 本身从未改变,只有值改变了......所以 React 认为状态从未改变!!! 。这是正确的原因吗?我不想使用数组。 如果我使用数组作为计数器,代码绝对可以正常工作。

我在这里缺少什么?

最佳答案

您应该始终以不变的方式更新状态或其任何字段:

handleDecrease = counterId => {
  // This is always Called
  this.setState(prevState => {
      const { oldCounterMap } = prevState;
      newCounterMap = new Map(oldCounterMap);
      const counter = oldCounterMap.get(counterId);
      newCounterMap.set(counterId, {...counter, value: counter.value - 1});
      return Object.assign({}, prevState, { counterMap: newCounterMap })
  });
}

说明:

首先,如果您需要根据旧值计算新的状态值,那么您应该使用setState的签名:setState(previousState => {}) 将当前状态作为参数传递给您。

然后,为了不可变地更新计数器,我们首先需要克隆 counterMap:

newCounterMap = new Map(oldCounterMap);

您可以看到这是一个克隆,因为 newCounterMap === oldCounterMapfalse

然后我们继续根据需要更新此 map :

newCounterMap.set(counterId, {...counter, value: counter.value - 1});

注意对象传播,这再次导致基于 counter 创建一个全新的对象(这只是一个很好的实践,即使不是非常必要)。

最后我们返回一个全新的对象来替换我们当前的状态。

return Object.assign({}, prevState, { counterMap: newCounterMap })

再次注意,我在这里使用了对象传播,这样我们既返回一个新对象,又保持其他值不变(不覆盖状态的其他条目)

关于reactjs - 如果ReactJS状态具有map属性,则更改map值不会反射(reflect)状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55195863/

相关文章:

javascript - 我可以将 React 组件放入 state 中吗?

javascript - 使用 ReactJS 隐藏/显示内容

ReactJS:警告:setState(...):无法在现有状态转换期间更新

javascript - 表格单元格中的工具提示定位

javascript - NextJS - 在页面组件加载时加载外部脚本

javascript - Youtube 在手机上嵌入自动播放

javascript - 从动态创建的子组件更改状态 - React

javascript - 与 setState 回调相比,使用 componentDidUpdate 有什么优势?

javascript - 静态方法中的 setState

javascript - 尽管已初始化,mapStateToProps 在 Redux 中始终返回未定义