Обработка формы React Hooks: обновление состояния объекта с помощью нескольких строковых элементов и одного элемента массива.

Я изучаю React, используя хуки для создания приложения. Я следил за учебником, однако я хотел бы внести в него некоторые изменения. У меня есть объект с несколькими строковыми элементами и одним элементом массива:

  const [recipe, setRecipe] = useState({
    title: '',
    description: '',
    ingredients: [],
    instructions: '',
    tags: 'none'
  }); 

В учебнике изначально были все строковые элементы, поэтому следующий код отлично работал для обновления состояния:

    setRecipe({ ...recipe, [e.target.name]: e.target.value });
  }

Пример одного из полей ввода, где все были похожи.

          <input
            type='text'
            placeholder='Title'
            name='title'
            value={title}
            onChange={onChange}
          />

Теперь, когда я изменил один из элементов на массив, он больше не работает. Я пробовал несколько способов сделать это, например:

 const [test, setTest] = useState({
    ingredients: ['bread', 'milk', 'honey']
  });

 const [query, setQuery] = useState('');

  const updateQuery = e => {

    setQuery(e.target.value);
  };

  const addItem = e => {
    e.preventDefault();

    setTest(test => ({ ingredients: [...test.ingredients, query] }));
  };

return (

          <div>
            <button className='btn btn-light btn-block' onClick={addItem}>
              Add ingredient
            </button>
            <input
              type='text'
              placeholder='Description'
              name='ingredients'
              value={ingredients}
              onChange=(updateQuery)
            />
          </div>
          <div>
            {test.ingredients.map(data => (
              <ul key={data}>{data}</ul>
            ))}
          </div>

  );

Я изо всех сил пытаюсь найти решение.

Помощь приветствуется.


person mexicanChica    schedule 30.03.2020    source источник
comment
Эта строка не вызвала ошибку, что ваша тестовая переменная уже объявлена? setTest(test => ({ ingredients: [...test.ingredients, query] }));   -  person Incepter    schedule 30.03.2020
comment
Может быть, хорошо объяснить, чего вы пытаетесь достичь с помощью этого примера?   -  person hurricane    schedule 30.03.2020


Ответы (3)


Предоставленный вами код нуждается в некотором форматировании (он же: onChange={onChange}, а не onChange, и ваше входное значение должно иметь query, а не ингредиенты)

Кроме того, вы не возвращали старое состояние при его редактировании.

Я добавил в ваше состояние целочисленное поле без массива

const [test, setTest] = React.useState({
    nonArray: 0,
    ingredients: ["bread", "milk", "honey"]
  });

И затем я изменил ваш addItem, чтобы он выглядел так:

const addItem = e => {
    e.preventDefault();
    setTest(old => ({ ...old, ingredients: [...old.ingredients, query] }));
    setQuery("");
  };

И, кажется, работает как шарм.

Пожалуйста, проверьте этот рабочие коды и ящик, который содержит в основном ваш код.

person Incepter    schedule 30.03.2020

Как я это вижу, вам нужно использовать useCallback в addItem, updateQuery, например

const updateQuery = useCallback(e => {

    setQuery(e.target.value);
  },[]);

const addItem = useCallback(e => {
    e.preventDefault();

    setTest(test => ({ ingredients: [...test.ingredients, query] }));
  },[query]);

Это принцип хуков, если вы хотите понять этот принцип, вы можете выполнить поиск Principle of useCallback.

Если вы хотите узнать простой способ, я могу сказать вам одну вещь. В компоненте рендеринга addItem есть запрос -> изменение состояния ->, но запрос addItem не может измениться

person Stark Jeon    schedule 30.03.2020
comment
Его проблема не в мемоизации, так как повторная функция эквивалентна использованию обратного вызова без отложений. - person Incepter; 30.03.2020

Проблема с этой строкой: setTest(test => ({ ingredients: [...test.ingredients, query] })

При работе с компонентами класса реакции было бы нормально установить состояние, не распространяя все предыдущее состояние, например this.setState({ ingredients: [...test.ingredients, query] }), потому что внутренняя реакция уже объединяет ваш новый объект, который вы передаете в this.setState, с предыдущим состоянием.

В ответных хуках React.useState не выполняет слияние, поэтому вам нужно объединить предыдущее состояние, например setState(test => ({ ...test, ingredients: [...test.ingredients, query] }).

edit: Также вы объявили переменную test в верхней части вашего компонента. Я рекомендую переименовать аргумент test внутри setTest во что-то другое.

person Chris    schedule 30.03.2020
comment
Вы проверили мой ответ, прежде чем ответить? ????‍♂️ - person Incepter; 30.03.2020