为从具有动态长度的字符串数组映射的 React 组件设置键

Setting keys for React components mapped from a string array with dynamic length

问题

这是一个问题表格,一个问题有很多答案。用户可以添加、编辑、删除表单中的答案。

答案存储在字符串数组中。我们将使用此数组来呈现答案输入及其对应的“删除”按钮。

我试过的:

我们如何解决这个问题?

代码沙盒link:https://codesandbox.io/s/multiplechoicequestionform-2h0vp?file=/src/App.js

import { useState } from "react";

function MultipleChoiceQuestionForm() {
  const [answers, setAnswers] = useState<string[]>([]);

  const addAnswer = () => setAnswers([...answers, ""]); // Add a new empty one at bottom

  const removeAnswerAtIndex = (targetIndex: number) => {
    setAnswers(answers.filter((_, index) => index !== targetIndex));
  };

  const onAnswerChangeAtIndex = (newAnswer: string, targetIndex: number) => {
    const newAnswers = [...answers];
    newAnswers[targetIndex] = newAnswer;
    setAnswers(newAnswers)
  };

  return <form>
    {answers.map((answer, index) =>
      <div
        // I think the problem is the key, how to set this correctly ?
        // Set to index: make removing elements has re-render errors 
        key={index}
        // key={answer}  // Lose focus on each character typed
        style={{ display: "flex" }}
      >
        <input type="text" onChange={(e) => onAnswerChangeAtIndex(e.target.value, index)} />
        <button onClick={(_) => removeAnswerAtIndex(index)}>Remove</button>
      </div>
    )}
    <button onClick={addAnswer}>Add</button>
  </form>
}

我想你忘了将你的答案值绑定到输入元素。现在你所有的输入都是不受控制的,这不是处理你添加或删除项目的动态表单的最佳方式,最好让它们受到控制。

就这样做:

<input
  type="text"
  value={answer}
  onChange={(e) => onAnswerChangeAtIndex(e.target.value, index)}
/>

Working Codesandbox example

这里的其他好的做法可能是使用一些其他结构作为答案,例如,使用 id 创建一个对象而不是字符串(您可以自己生成它们,最简单的方法是使用 Math.random()) 和 value 属性 每个答案,这样你就可以使用那个 id 作为真正的密钥。