Search code examples
arraysreactjsreact-hooksuser-inputsetstate

React Hooks Form Handling: Update the state of an object with multiple string items and one array item


I'm learning React using hooks to make an application. I've been following a tutorial however I would like to make some changes to it. I have an object with multiple string items and one array item:

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

The tutorial originally had all string items so the following code worked perfectly to update the state:

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

Example of one of the input fields which were all were similar.

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

Now that i've changed one of the items to an array, it no longer works. I've tried several ways to do it, for example:

 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>

  );

I'm struggling to find a solution.

Help would be appreciated.


Solution

  • The code you provided needs some formatting (aka: onChange={onChange} rather than onChange and your input value to have query rather than ingredients)

    Also, you were not retaking the old state when editing it.

    I added to your state a non array integer field

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

    And then I changed you addItem to look like:

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

    And it seems to be working like a charm.

    Please check this working codesandbox that contains basically your code.