reactjs - 如果 ReactJS 的 state 有 map 属性,改变 map 的值并不会反映 state
问题描述
我有一个名为 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 })
});
}
解释:
首先,如果您需要根据旧值计算状态的新值,那么您应该使用setState
:的这个签名,setState(previousState => {})
它将当前状态作为参数传递给您。
然后为了不可变地更新计数器,我们首先需要克隆counterMap:
newCounterMap = new Map(oldCounterMap);
你可以看到这是一个克隆,因为newCounterMap === oldCounterMap
是false
.
然后我们继续并根据需要更新此地图:
newCounterMap.set(counterId, {...counter, value: counter.value - 1});
注意对象的传播,这再次导致创建一个全新的对象counter
(这只是一个很好的做法,即使它不是非常必要的)。
最后我们返回一个全新的对象来替换我们当前的状态。
return Object.assign({}, prevState, { counterMap: newCounterMap })
再次注意,我在这里使用了对象扩展,这样我们既返回一个新对象,又保持其他值不变(不覆盖 的其他条目state
)
推荐阅读
- html - 如何将下载的 mp4 视频嵌入到 react 应用程序中?
- python - 左连接 DataFrame,其中左侧 DataFrame 中的 Date 包含在基于右侧 DataFrame 中的 Date 的 Dates 范围内
- python - 为什么`python -m profile scpt.py`中的tottime总和不接近总运行时间?
- spring-boot - 如何使用 Spring data JPA 在 @Query 注释中动态传递列名
- c++ - Linux测量时间问题!std::chrono、QueryPerformanceCounter、clock_gettime
- android-studio - Lint 在组装发布目标时发现致命错误 - minSdkVersion 26 到 21
- javascript - 如何在应用 querySelector 之前等到模态主体加载
- oracle19c - Oracle 19c 不支持 SYS_CONTEXT 函数中的“AUTHENTICATION_TYPE”参数。现在有什么替代方案?
- visual-studio-2010 - 从 git-bash 启动 devenv 会产生构建错误
- c# - 从蓝牙特性更新视图模型中的值