【问题标题】:React hooks - cannot type in input field [NOT duplicate]反应钩子 - 无法输入输入字段[不重复]
【发布时间】:2020-05-07 10:35:05
【问题描述】:

您可以在此处查看完整代码: CODESANDBOX LINK

这真的很奇怪。 我有一个输入字段列表,这些字段根据按钮单击动态呈现

const newFields = (index) =>
<div>
    <input value={inputs[index].name}  onChange={e => handleNameInput(e,index)} />
    <input value={inputs[index].age} type="number" onChange={e => handleAgeInput(e,index)} />
    <Button onClick={() => setInputArray(inputArray => [...inputArray, newFields(++index)])}>Add</Button>
</div>

我正在尝试存储输入的值并在更改时更新它们。但正如标题中所述,我无法在输入字段中输入,一旦我单击一个字符,输入就会失去焦点。我不知道为什么会这样。

这里是状​​态和handleInput函数:

  let [inputs, setInputs] = useState(Array.apply(null, Array(100)).map(function () { return {
    name: '',
    age: ''
  } }));

const handleNameInput = (e, i) =>{
  let tempArr = new Array();
  tempArr = [...inputs];
  tempArr[i].name = e.target.value;
  setInputs([...tempArr]);
}

//handleAgeInput is exactly the same

【问题讨论】:

  • 闭包中有一些问题,这是肯定的,但我不明白你是如何使用inputArrayinput 的。你能给我解释一下吗?因为,据我了解,在inputArray 中您正在保存HTML 元素,而在input 中您只是在保存值.. 对吗?这是强制性的吗?因为我很确定你可以通过input 数组实现你想要的。我可以给你举个例子
  • 我正在使用输入数组动态显示字段,页面开始时显示一组输入字段。然后,如果您单击该按钮,它将添加一组新的输入字段。我想要做的是将每个输入字段中的值存储在输入数组中
  • 请查看沙盒链接以查看应用程序,这很容易理解问题然后codesandbox.io/s/laughing-leftpad-27woh?file=/src/App.js
  • 我确实查看了沙箱,并且确实了解您想要实现的目标,但我想知道您的某些实现选择是否是故意做出的,因为有更简单的方法来获得您的需求.例如,就像在接受的答案中一样。
  • @Jolly 好吧,我在这里尝试简化程序并提及唯一相关的部分,但我的实际程序有点复杂。这就是为什么您可能会找到更简单的方法来实现相同的目标。但我唯一想了解的是为什么我不能在字段中输入。还是谢谢

标签: reactjs react-hooks


【解决方案1】:

我认为您的主要问题是重复使用数组。事实是,您只需要一组数据。因此,您需要围绕它构建组件。如果您在状态上创建另一个数组,则会增加复杂性,并导致您当前的问题。

了解为什么没有更新

你是onChange 函数调用更新inputs 数组状态。但是,您正在渲染inputArray,他没有任何改变。没有setInputArray 调用所以,没有重新渲染。

提案

有我理解的你需要的提案实施:

function App() {
  let [inputArray, setInputArray] = useState([{
    name: "",
    age: ""
  }]);

  const handleNameInput = useCallback(
    (e, i) => {
      inputArray[i].name = e.target.value;
      setInputArray([...inputArray]);
    },
    [inputArray]
  );

  const handleAgeInput = useCallback(
    (e, i) => {
      inputArray[i].age = e.target.value;
      setInputArray([...inputArray]);
    },
    [inputArray]
  );

  const handleNewField = useCallback(() =>
    setInputArray(inputArray => [...inputArray, {
      name: "",
      age: ""
    }]),
    []
  );

  return (
    <div className="App">
      {inputArray.map((element, i) => (
        <div>
          <input
            value={element.name}
            onChange={e => handleNameInput(e, i)}
          />
          <input
            value={element.age}
            type="number"
            onChange={e => handleAgeInput(e, i)}
          />
          <button
            onClick={handleNewField}>
            Add
          </button>
        </div>
      ))}
    </div>
  );
}

根据你的需要,也许你应该适应它。有一些方法可以避免重新渲染整个列表。但是这样你可以编辑所有字段

另一种正确的方法是将每个字段分组为另一个 Component.with 独立状态。

如果您希望按钮只出现一次,请将他从循环中移出。

如果您只想显示最后设置的字段,请使用 inputArrays[inputArray.length] 而不是全部循环。

解释:

您正在渲染一组组件 { inputArray.map((e, i) =&gt; { return &lt;div key={i}&gt; {e} &lt;/div&gt;; })},其中 e 应该是一个组件。

另一方面,您正在维护一个“隐藏”第一个数组的数据数组。

据我所知,您的用例的主要概念应该是直接从您的数据(您的数据数组)呈现您的组件。 这样你就只有一个事实来源。

【讨论】:

  • 你能简单解释一下我到底犯了什么错误吗?顺便说一句,代码可以工作,所以谢谢。
  • 我只是编辑我的答案的顶部,如果它对你来说足够了。如果我错过了什么,请毫不犹豫地问我:)。我在您的代码中看到了很多错误,所以我不知道这是否是对更复杂组件的简化。或者,如果你没有一些知识(如果你问问题,这很明显 xD)
  • 实际上它是一个更复杂程序的一部分,但我在这里尝试对其进行简化,以便每个人都能轻松解决。所以我实际上需要这两个数组,但我会相应地修改我的代码,我唯一需要了解的是为什么我不能输入字段?
  • 好的,所以我将添加另一个解释来回答这个确切的问题:)
  • TL;DR : setInputArray 所以inputArray 没有任何变化,因此您构建的newFields 组件不会重新渲染。这就是为什么我的核心答案是避免这两种状态。
猜你喜欢
  • 2021-10-17
  • 2021-08-08
  • 1970-01-01
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-27
相关资源
最近更新 更多