如果ReactJS状态具有map属性,则更改映射值不会反映状态

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如果ReactJS状态具有map属性,则更改映射值不会反映状态相关的知识,希望对你有一定的参考价值。

我有一个名为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 );

这在UI中不起作用。

计数器值的更改不会反映在UI中。我的想法是因为地图本身从未改变过,只有价值发生变化......所以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 )
  );

说明:

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

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

newCounterMap = new Map(oldCounterMap);

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

然后我们继续并按照我们的喜好更新此地图:

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

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

最后,我们返回一个全新的对象来取代我们当前的状态。

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

再次注意,我在这里使用了对象传播,因此我们都返回一个新对象并保持其他值不变(不覆盖state的其他条目)

以上是关于如果ReactJS状态具有map属性,则更改映射值不会反映状态的主要内容,如果未能解决你的问题,请参考以下文章

Mapstruct 映射:如果所有源参数属性为空,则返回空对象

Mapstruct 映射:如果所有源参数属性为空,则返回空对象

如果内容与另一个属性值匹配,则更改标签前景

在Java 8中,如果map具有重复值,则会出现重复值异常

Reactjs 状态初始化一个值数组

NHibernate:映射具有属性的复杂值类型?