React Hooks 表单处理:使用多个字符串项和一个数组项更新对象的状态

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

我正在学习使用钩子制作应用程序的 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>

  );

我正在努力寻找解决方案。

不胜感激。

在我看来,您需要在 addItem 中使用 useCallback,如 updateQuery

const updateQuery = useCallback(e => {

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

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

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

就是hooks原理,想了解这个原理的可以搜索Principle of useCallback

如果你想知道简单的方法,我可以告诉你一件事。 在渲染组件时,addItem有query -> state change -> 但是addItem的query不能改变

您提供的代码需要一些格式(又名: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("");
  };

它似乎很有魅力。

请检查此 working codesandbox,其中基本上包含您的代码。

这一行有问题:setTest(test => ({ ingredients: [...test.ingredients, query] })

当使用 react class 组件时,设置状态而不像 this.setState({ ingredients: [...test.ingredients, query] }) 那样传播整个先前的状态会很好,因为内部 react 已经合并了您传递给 [=12] 的新对象=] 与以前的状态。

在 React 钩子中,React.useState 不进行合并,因此您必须像 setState(test => ({ ...test, ingredients: [...test.ingredients, query] }).

那样合并之前的状态

编辑:您还在组件的顶部声明了变量 test。我建议将 setTest 中的 test 参数重命名为其他名称。