Реагируйте на useState, как изменить первый объект в массиве - PullRequest
0 голосов
/ 03 августа 2020

SANDBOX LINK

Я использую FormControl, чтобы попытаться обновить свое состояние, по умолчанию const [numberOfChildren, updateNumberOfChildren] = useState([{age: undefined}]); Я хочу изменить первый объект в массиве, когда пользователь щелкает кнопку, а затем вводит значение в поле ввода. Я пытаюсь обновить age другим useState В настоящее время первым объектом массива является {age: undefined} и он не обновляется с помощью useState hook

Код выглядит так:

 <FormControl
 placeholder="Age"
 aria-label="Age"
 aria-describedby="basic-addon2"
 onChange={async (e) => {
       await updateAge(e.target.value);
 }}
 />

обновляется кнопкой

<Button
  className="align-button"
  onClick={async (e) => {
         e.preventDefault();
         if(numberOfChildren.length < 1) {
                   await updateNumberOfChildren((children) => [
                         ...children
                   ]);
                   } else {
                      await updateNumberOfChildren((children) => [
                       ...children,
                         { childAge: age },
                       ]);
                       }

                        console.log(numberOfChildren)
                            }}
                            style={{ width: "100%" }}
                            variant="outline-primary"
                            type="submit"
                            size="lg"
                        >
                            Add Child
                        </Button>{" "}

Вот песочница, посмотрите на консоль для вывода SANDBOX

1 Ответ

1 голос
/ 04 августа 2020

То, как вы это делали, используя const [age, updateAge] = useState(undefined);, не даст вам того, что вы хотите, потому что, сделав это, вы обновите только последний добавленный дочерний элемент, поэтому вы не сможете go вернуться к первому и изменить или даже измените любые предыдущие дочерние элементы после их добавления, поскольку текущая настройка не имеет возможности различить, какой из них вы пытаетесь изменить.

Итак, идея заключается в том, что вам нужно идентифицировать каждый объект в массиве с помощью что-то уникальное, поэтому я изменил структуру объекта на следующее:

const [numberOfChildren, updateNumberOfChildren] = useState([
        { id: 1, age: undefined }
      ]);

А вот как вы обновляете состояние, объясняя каждую строку:

// Update numberOfChildren state
  function updateData(e) {
    // Grab the id of the input element and the typed value
    const { id, value } = e.target;
    // Find the item in the array that has the same id
    // Convert the grabed id from string to Number
    const itemIndex = numberOfChildren.findIndex(
      item => item.id === Number(id) 
    );

    // If the itemIndex is -1 that means it doesn't exist in the array
    if (itemIndex !== -1) {
      // Make a copy of the state
      const children = [...numberOfChildren];
      // The child item
      const child = children[itemIndex];
      // Update the child's age
      children.splice(itemIndex, 1, { ...child, age: value });
      // Update the state
      updateNumberOfChildren(children);
    }
  }

И когда вы добавляете новый дочерний элемент, последний добавленный дочерний элемент будет иметь идентификатор длины состояния numberOfChildren плюс 1, поскольку я использовал 1 в качестве отправной точки:

onClick={e => {
  e.preventDefault();
  updateNumberOfChildren([
    ...numberOfChildren,
    { id: numberOfChildren.length + 1, age: undefined }
  ]);
}}

Наконец, если вы хотите проверить какое-либо значение состояния, не используйте console.log() после setState(), потому что setState() равно async, поэтому вы не получите изменения сразу, и, поскольку вы используете хуки, единственный способ обойти это useEffect():

// Check the values of numberOfChildren whenever they get updated
  useEffect(() => {
    console.log("numberOfChildren", numberOfChildren);
  }, [numberOfChildren]);

Вот песочница * 10 23 *. Надеюсь, теперь все предельно ясно.

...