如何在React功能组件中立即更新状态?

时间:2020-01-07 17:31:10

标签: javascript reactjs functional-programming components

我是React的新手,对功能组件的生命周期感到非常困惑。 假设我有许多类型的输入:复选框,a,b,c和d。它们的值分别是a,b,c和d。

const OnBoarding = () => {
  const [isChecked, setIsChecked] = useState({
    a: false,
    b: false,
    c: false,
    d: false
  });
  
  const [allCheckedItems, setAllCheckedItems] = useState([]);
  
  //Write function that pushes checked value to state array when clicked
  const onChecked = e => {
    setIsChecked({
      ...isChecked,
      [e.target.value]: e.target.checked
    });
    const all = Object.keys(isChecked).filter(function(key){
      return isChecked[key] === true;
    });
    console.log("all items that are TRUE : " + all);
    setAllCheckedItems([all]);
    console.log("allCheckedItems : " + allCheckedItems);
  };
  
  useEffect(() => {
    console.log(isChecked);
  });
  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

我有一个功能组件,其状态为类型为对象的状态,具有许多属性,所有布尔值,如下所示:

const [isChecked, setIsChecked] = useState({
  a: false,
  b: false,
  c: false,
  d: false
})

我还有一个其他状态,它是 array ,我们称之为 allCheckedItems ,它应该是 isChecked的所有键的数组 strong>设置为true。

const [allCheckedItems, setAllCheckedItems] = useState([]);

通过一个功能onChecked,当复选框被选中,它的值在在器isChecked 对象集为

我调用useEffect(),在其中编写了一个过滤器函数来过滤所有正确的属性。所有设置为true的属性都存储在名为“ all” 的数组中。

我的问题出在我必须更新数组 allCheckedItems 的状态时。如果我写在useEffect钩子中:

setAllCheckedItems([all]);

我遇到无限循环。如果我在 onChecked函数中编写它,则每当我单击一个复选框时,我在控制台中登录的allCheckedItems的状态就会一键显示。 就像,我单击以选中“ a”,它记录:

[]

然后我单击“ b”,它记录:

[a]

然后单击“ c”,它记录:

[a, b]

我希望当我选中一个框时,两个状态都会更新,并且allItemsChecked会立即记录所有已检查的项目... 有人可以向我解释这种行为吗?几天来,这让我头疼。

1 个答案:

答案 0 :(得分:2)

useEffect挂钩给您带来无限循环的原因是,在每次渲染未提供第二个参数时,都会在每个渲染之后触发useEffect。官方的react documentation中有针对react钩子的声明,如果第二个参数中的值未更改,则组件将跳过效果的应用。

如果我们将setAllCheckedItems()设置为useEffect()的第二个参数,则在[isChecked]内调用useEffect()可以正常工作(这将确保仅当isChecked的值已更改)

useEffect(() => {
  setAllCheckedItems([all]);
}, [isChecked]);

我建议您通过在复选框的setAllCheckedItems()事件中调用onClick来降低代码的复杂性,因为每次选中复选框时都会运行该代码。您可以重构onChecked方法,以使setAllCheckedItems()不依赖于isChecked状态。

const onChecked = (e) => {
  // get current checked state, and update it with the checkbox values
  const updatedChecked = {
    ...isChecked,
    [e.target.value]: e.target.checked
  }
  // update isChecked state
  setIsChecked(updatedChecked);
  const all = Object.keys(updatedChecked).filter(function(key){
    return updatedChecked[key] === true;
  });
  // update allCheckedItems state
  setAllCheckedItems([all]);
}

如您所见,我们已经创建了isChecked状态的副本,并使用新值更新了该副本。此外,我们使用该副本返回已检查的密钥。之后,我们更新各自的状态。