在 useCallback 挂钩中使用 useState 时出现问题
Problem using useState inside useCallback hook
我遇到一个问题,useCallback 函数中的 useState 挂钩“setSelectAll(!selectAll)”更新了值,但该句子下面的条件使用的是旧的 selectAll 值,所以我必须点击两次才能让它工作,我不知道为什么,任何帮助都会非常感谢!
我有这个 useCallback 钩子,它在我按下按钮时执行
<Button onClick={onSelectAll}>{selectAll ? t`Deselect All` : t`Select All`}</Button>
这是我的回电,
const onSelectAll = useCallback(() => {
setSelectAll(!selectAll);
if(selectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);```
你正在直接改变状态,这会导致问题,
你需要让反应更新状态,如下例
setSelectAll(prevState => !prevState)
为了避免在这种情况下出现 React 生命周期问题,您需要根据之前的状态设置状态。
像这样:
setSelectAll(prevSelectAllState => !prevSelectAllState);
在您的具体示例中,它应该是这样的:
const onSelectAll = useCallback(() => {
setSelectAll(prevSelectAllState => !prevSelectAllState);
if(newSelectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);
use/setState
是同步的,因此紧跟其后的任何代码 运行 直到组件 re-renders 之后才会看到状态更改的结果。相反,只需在真实版本更改之前使用更改后的版本来模拟更改:
const onSelectAll = useCallback(() => {
const newSelectAll = !selectAll; // <--
setSelectAll(newSelectAll);
if(newSelectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);
你需要了解 React 组件的生命周期。
useEffect
将在 re-render 中的状态更改后被更新状态触发。
而且useCallback
功能也变了。
因此您可以在内部调用您的回调函数,而无需通过更改状态直接调用。
const onSelectAll = useCallback(() => {
if(selectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);
<Button onClick={setSelectAll(prevSelectAllState => !prevSelectAllState);}>{selectAll ? t`Deselect All` : t`Select All`}</Button>
我遇到一个问题,useCallback 函数中的 useState 挂钩“setSelectAll(!selectAll)”更新了值,但该句子下面的条件使用的是旧的 selectAll 值,所以我必须点击两次才能让它工作,我不知道为什么,任何帮助都会非常感谢!
我有这个 useCallback 钩子,它在我按下按钮时执行
<Button onClick={onSelectAll}>{selectAll ? t`Deselect All` : t`Select All`}</Button>
这是我的回电,
const onSelectAll = useCallback(() => {
setSelectAll(!selectAll);
if(selectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);```
你正在直接改变状态,这会导致问题, 你需要让反应更新状态,如下例
setSelectAll(prevState => !prevState)
为了避免在这种情况下出现 React 生命周期问题,您需要根据之前的状态设置状态。
像这样:
setSelectAll(prevSelectAllState => !prevSelectAllState);
在您的具体示例中,它应该是这样的:
const onSelectAll = useCallback(() => {
setSelectAll(prevSelectAllState => !prevSelectAllState);
if(newSelectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);
use/setState
是同步的,因此紧跟其后的任何代码 运行 直到组件 re-renders 之后才会看到状态更改的结果。相反,只需在真实版本更改之前使用更改后的版本来模拟更改:
const onSelectAll = useCallback(() => {
const newSelectAll = !selectAll; // <--
setSelectAll(newSelectAll);
if(newSelectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);
你需要了解 React 组件的生命周期。
useEffect
将在 re-render 中的状态更改后被更新状态触发。
而且useCallback
功能也变了。
因此您可以在内部调用您的回调函数,而无需通过更改状态直接调用。
const onSelectAll = useCallback(() => {
if(selectAll) {
let newItemsSelected = [...itemsSelected];
arrayList.forEach(item => {
newItemsSelected.push(item.id);
})
setItemsSelected(newItemsSelected);
onSelectedChange(newItemsSelected);
} else {
setItemsSelected([]);
}
}, [selectAll, itemsSelected]);
<Button onClick={setSelectAll(prevSelectAllState => !prevSelectAllState);}>{selectAll ? t`Deselect All` : t`Select All`}</Button>