在 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>