Как сразу обновить состояние в функциональном компоненте React? - PullRequest
0 голосов
/ 07 января 2020

Я новичок в React, и я очень озадачен жизненным циклом функционального компонента. Допустим, у меня есть много входов типа: флажок, а, б, c и д. Их значения 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
})

У меня есть другое состояние, которое является массивом , назовем его allCheckedItems , который должен быть массивом всех ключей isChecked установлен в значение true.

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

Если функция включена, при установленном флажке ее значение в объекте isChecked устанавливается равным true .

Я вызываю useEffect (), в котором я написал функцию фильтра для фильтрации всех свойств, которые являются истинными. Все свойства со значением true хранятся в массиве с именем "all" .

Моя проблема возникает, когда мне нужно обновить состояние массива allCheckedItems . Если я напишу в хуке useEffect:

setAllCheckedItems([all]);

, я получу бесконечное число l oop. Если я запишу его в своей функции onChecked , всякий раз, когда я нажимаю на флажок, состояние всех элементов CheckCheckedItems, которые я регистрирую в консоли, является ПОЗЖЕ на один щелчок. Например, я нажимаю, чтобы проверить «а», и он записывает:

[]

Затем я нажимаю «б», и он записывает:

[a]

Затем я нажимаю «c "и он регистрирует:

[a, b]

Мне бы хотелось, чтобы при установке флажка обновлялись оба состояния и чтобы allItemsChecked регистрировал все элементы, проверенные немедленно ... Может кто-нибудь объяснить мне такое поведение? Уже несколько дней у меня болит голова.

1 Ответ

2 голосов
/ 07 января 2020

Причина, по которой хук useEffect дает вам бесконечное значение l oop, заключается в том, что useEffect срабатывает после каждого рендеринга, когда ему не передается второй аргумент. Это указано в официальной реакции документации для реагирующих ловушек, и что компонент пропустит применение эффекта, если значения во втором аргументе не изменились.

При вызове 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, и обновить копию с новыми значениями. Кроме того, мы используем эту копию для возврата проверенных ключей. После чего мы обновляем соответствующие состояния.

...