Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如果ReactJS状态具有映射属性,则更改映射值不会反映该状态_Reactjs_Setstate - Fatal编程技术网

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

如果ReactJS状态具有映射属性,则更改映射值不会反映该状态,reactjs,setstate,Reactjs,Setstate,我有一个叫做计数器的组件 export default class Counters extends Component { state = { counterMap: {} }; noOfComponents = 5; componentWillMount() { var counterMap = new Map(); for (var i = 0; i < this.noOfComponents; i++) { var counte

我有一个叫做计数器的组件

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>;
  }
}
这在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 })
  });
}
说明:

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

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

newCounterMap = new Map(oldCounterMap);
您可以看到这是一个克隆,因为
newCounterMap==oldCounterMap
false

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

newCounterMap.set(counterId, {...counter, value: counter.value - 1});
请注意对象扩展,这会再次导致基于
计数器创建一个全新的对象(这只是一个良好的实践,即使不是非常必要)

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

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

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

为什么不使用数组?这似乎更适合此用例。如果您使用
setState
更改状态,react将知道它已更改。因为这是一个实验。在实际场景中,我希望为服务器加载大量数据[当然是延迟加载]。每个数据都有一个来自Db的唯一UUID,我想创建每个UUID和数据本身的映射。因此,我将为每个数据创建组件,并根据每个组件的id==UUID处理交互。@Amir:谢谢你的回答,我认为react的状态是map对象的内存位置或每个键的内存。。。。现在每个关键点又是一个对象。。。所以没有更改内存位置。。我的意思是这是我的理解。。。但我还是不确定。。。你能在你的经验中使用状态映射吗?你不应该改变状态或它的任何字段。您使用的
setState
是错误的。您应该以
setState(previousState=>{/*…*/})
的形式使用它,还应该创建一个全新的
计数器映射
并替换它,而不是更新它。因为状态是不可变的
return Object.assign({}, prevState, { counterMap: newCounterMap })