setState 不更新值
setState not updating value
我有一个 onClick()
用于基于 react-photo-gallery
的图像 select 或者(onClick()
基于 selectPhoto(event, obj)
中显示的函数 react-photo-gallery
示例代码位于 https://codesandbox.io/s/o7o241q09?from-embed).
我改编的代码版本已被改编为包含图像数量的计数器 selected(这样,例如,我可以动态地向用户提供下载功能 如果 selected>0)
我的代码如下所示:
selectPhoto(event, obj) {
let photos = this.state.apiItems;
photos[obj.index].selected = !photos[obj.index].selected;
this.setState({ apiItems: photos });
let localSelectedCount=0;
this.state.apiItems.forEach(function(pVal,pIndex) {
if (pVal.selected) {
localSelectedCount = localSelectedCount + 1;
}
});
this.setState({selectedImagesCount:localSelectedCount});
console.log(localSelectedCount);
console.log(this.state.selectedImagesCount);
//
}
在我的 class 顶部,我定义了初始状态:
constructor() {
super();
this.state = {
selectedImagesCount:0,
apiItems: []
};
this.selectPhoto = this.selectPhoto.bind(this);
}
我遇到的问题是 localSelectedCount
完美地递增和递减。然而 this.state.selectedImagesCount
总是落后一个。
因此,例如,如果我 select 一张图像,然后 deselect 一张图像,console.log()
将输出:
1
0
0
1
当预期输出当然是:
1
1
0
0
我正在使用 Node v10.14.1 和 React 16.6.3。
React 就是这样工作的。 setState 调用是异步的。当下一次渲染触发时,所有先前的 setState 将完成。
您可以向 setState 添加回调。它会在 setState 发生时调用。如果您将日志放在那里,它将显示正确的值。
this.setState({selectedImagesCount:localSelectedCount}, () => console.log(this.state.selectedImagesCount));
this.state
不应与 setState
一起使用。由于状态更新是异步的,这可能会导致竞争条件。
状态 updater function 应该解决问题:
...
this.setState({ apiItems: photos });
this.setState(state => {
let localSelectedCount=0;
// is a good use case for array reduce
state.apiItems.forEach(function(pVal,pIndex) {
if (pVal.selected) {
localSelectedCount = localSelectedCount + 1;
}
})
return {selectedImagesCount:localSelectedCount};
});
异步更新的另一个问题是 console.log
存在竞争条件。 setState
更新值,但不是在调用 console.log
的那一刻。这就是回调参数的用途。应该是:
...
this.setState({ apiItems: photos });
this.setState(state => {
let localSelectedCount=0;
// is a good use case for array reduce
state.apiItems.forEach(function(pVal,pIndex) {
if (pVal.selected) {
localSelectedCount = localSelectedCount + 1;
}
})
return {selectedImagesCount:localSelectedCount};
}, () => {
console.log(this.state.selectedImagesCount);
});
我有一个 onClick()
用于基于 react-photo-gallery
的图像 select 或者(onClick()
基于 selectPhoto(event, obj)
中显示的函数 react-photo-gallery
示例代码位于 https://codesandbox.io/s/o7o241q09?from-embed).
我改编的代码版本已被改编为包含图像数量的计数器 selected(这样,例如,我可以动态地向用户提供下载功能 如果 selected>0)
我的代码如下所示:
selectPhoto(event, obj) {
let photos = this.state.apiItems;
photos[obj.index].selected = !photos[obj.index].selected;
this.setState({ apiItems: photos });
let localSelectedCount=0;
this.state.apiItems.forEach(function(pVal,pIndex) {
if (pVal.selected) {
localSelectedCount = localSelectedCount + 1;
}
});
this.setState({selectedImagesCount:localSelectedCount});
console.log(localSelectedCount);
console.log(this.state.selectedImagesCount);
//
}
在我的 class 顶部,我定义了初始状态:
constructor() {
super();
this.state = {
selectedImagesCount:0,
apiItems: []
};
this.selectPhoto = this.selectPhoto.bind(this);
}
我遇到的问题是 localSelectedCount
完美地递增和递减。然而 this.state.selectedImagesCount
总是落后一个。
因此,例如,如果我 select 一张图像,然后 deselect 一张图像,console.log()
将输出:
1
0
0
1
当预期输出当然是:
1
1
0
0
我正在使用 Node v10.14.1 和 React 16.6.3。
React 就是这样工作的。 setState 调用是异步的。当下一次渲染触发时,所有先前的 setState 将完成。 您可以向 setState 添加回调。它会在 setState 发生时调用。如果您将日志放在那里,它将显示正确的值。
this.setState({selectedImagesCount:localSelectedCount}, () => console.log(this.state.selectedImagesCount));
this.state
不应与 setState
一起使用。由于状态更新是异步的,这可能会导致竞争条件。
状态 updater function 应该解决问题:
...
this.setState({ apiItems: photos });
this.setState(state => {
let localSelectedCount=0;
// is a good use case for array reduce
state.apiItems.forEach(function(pVal,pIndex) {
if (pVal.selected) {
localSelectedCount = localSelectedCount + 1;
}
})
return {selectedImagesCount:localSelectedCount};
});
异步更新的另一个问题是 console.log
存在竞争条件。 setState
更新值,但不是在调用 console.log
的那一刻。这就是回调参数的用途。应该是:
...
this.setState({ apiItems: photos });
this.setState(state => {
let localSelectedCount=0;
// is a good use case for array reduce
state.apiItems.forEach(function(pVal,pIndex) {
if (pVal.selected) {
localSelectedCount = localSelectedCount + 1;
}
})
return {selectedImagesCount:localSelectedCount};
}, () => {
console.log(this.state.selectedImagesCount);
});