html table 正在无缘无故地复制默认值
html table is duplicating defaultValue's for no apparent reason
我有一些数据显示在 table 中。当我使用 JS 添加 table 数据单元格 (td) 时,前一个 table 数据单元格 (td) 的 defaultValue 和 innerText 被复制到新的 table 数据 (td) 中。我不明白为什么会这样?我只是添加了一个新的 html 元素,本质上,它与我要说的已经存在的元素无关。
const [dataSet, setDataSet] = useState([
{
City: "Amsterdam",
Provence: "North-Holland"
},
{
City: "Rotterdam",
Provence: "South-Holland"
}
]);
const newCity = () => {
const city = [
{
City: "Groningen",
Provence: "Groningen"
}
];
setDataSet(city);
};
<button onClick={newCity}>Add city</button>
<table>
<tr>
<th>City</th>
<th>Provence</th>
</tr>
{dataSet.map(city => (
<tr>
<td>
<input defaultValue={city.City}/>
</td>
<td>
<input defaultValue={city.Provence}/>
</td>
</tr>
)}
</table>
因此,当我单击 'newCity button' 时,会添加一个新的 table 行 (tr),但不会使用正确的数据填充 table 数据单元格 (td) (城市:'Groningen',普罗旺斯:'Groningen') 它使用来自前一个 table 行 (tr) 的数据填充 td(城市:'Amsterdam',普罗旺斯:'North-Holland').这对我来说真的很奇怪,因为我只添加了一个新的 html 元素,它与 table 行 (tr) 无关,因为它在相同的 table 中。
这是一个代码框 link 以查看实际行为:
https://codesandbox.io/s/dry-water-rss2m8?file=/src/App.js
为什么会这样?
您需要在项目上设置一个键
{dataSet.map((city) => (
<tr key={city.City}>
...
等等
这里有两件重要的事情需要考虑。
首先,您的程序正在输出警告:
Warning: Each child in a list should have a unique "key" prop.
始终 处理警告。他们在那里是有原因的!
其次,您正在处理一个 默认(相对于 当前)值。
当您用新数组替换数组时,React 会生成新的 JSX 并将其与现有的 DOM 进行比较。
第一个 行具有相同(缺少)键,因此它更改了现有行的默认值。 (second 行不再存在,因此将其删除)。
通过以下方式更改默认值没有任何效果:输入 已经 有值,它们将继续显示。
您可以给生成的行键:
<tr key={something}>
…但你需要弄清楚那是什么东西。
您可能会使用城市名称,但它似乎是一条可能会更改的数据 — 因此更改城市名称会使它看起来像一个新行,而不是对现有行的更新。
您可以考虑在创建对象时使用 uuid module 生成唯一 ID。
您还可以通过传递值而不是默认值来进行输入 controlled。这将要求您在编辑时更新传递给它们的值。
首先,原生 Input 元素没有 defaultValue 属性。查看 MDN 中的属性列表。它只有值和占位符。
其次,如果要向数据集中添加新城市,必须将 city-object 合并到数组中,而不是替换它。
setDataSet(currentDataSet => {
return [...currentDataSet, city]
})
我猜是因为你在使用不受控制的组件。
如果您希望输入值反映状态变化,您需要使用该值而不是默认值,并且您可能还需要一个 onChange 处理程序。
<input value={city.City} />
我有一些数据显示在 table 中。当我使用 JS 添加 table 数据单元格 (td) 时,前一个 table 数据单元格 (td) 的 defaultValue 和 innerText 被复制到新的 table 数据 (td) 中。我不明白为什么会这样?我只是添加了一个新的 html 元素,本质上,它与我要说的已经存在的元素无关。
const [dataSet, setDataSet] = useState([
{
City: "Amsterdam",
Provence: "North-Holland"
},
{
City: "Rotterdam",
Provence: "South-Holland"
}
]);
const newCity = () => {
const city = [
{
City: "Groningen",
Provence: "Groningen"
}
];
setDataSet(city);
};
<button onClick={newCity}>Add city</button>
<table>
<tr>
<th>City</th>
<th>Provence</th>
</tr>
{dataSet.map(city => (
<tr>
<td>
<input defaultValue={city.City}/>
</td>
<td>
<input defaultValue={city.Provence}/>
</td>
</tr>
)}
</table>
因此,当我单击 'newCity button' 时,会添加一个新的 table 行 (tr),但不会使用正确的数据填充 table 数据单元格 (td) (城市:'Groningen',普罗旺斯:'Groningen') 它使用来自前一个 table 行 (tr) 的数据填充 td(城市:'Amsterdam',普罗旺斯:'North-Holland').这对我来说真的很奇怪,因为我只添加了一个新的 html 元素,它与 table 行 (tr) 无关,因为它在相同的 table 中。
这是一个代码框 link 以查看实际行为: https://codesandbox.io/s/dry-water-rss2m8?file=/src/App.js
为什么会这样?
您需要在项目上设置一个键
{dataSet.map((city) => (
<tr key={city.City}>
... 等等
这里有两件重要的事情需要考虑。
首先,您的程序正在输出警告:
Warning: Each child in a list should have a unique "key" prop.
始终 处理警告。他们在那里是有原因的!
其次,您正在处理一个 默认(相对于 当前)值。
当您用新数组替换数组时,React 会生成新的 JSX 并将其与现有的 DOM 进行比较。
第一个 行具有相同(缺少)键,因此它更改了现有行的默认值。 (second 行不再存在,因此将其删除)。
通过以下方式更改默认值没有任何效果:输入 已经 有值,它们将继续显示。
您可以给生成的行键:
<tr key={something}>
…但你需要弄清楚那是什么东西。
您可能会使用城市名称,但它似乎是一条可能会更改的数据 — 因此更改城市名称会使它看起来像一个新行,而不是对现有行的更新。
您可以考虑在创建对象时使用 uuid module 生成唯一 ID。
您还可以通过传递值而不是默认值来进行输入 controlled。这将要求您在编辑时更新传递给它们的值。
首先,原生 Input 元素没有 defaultValue 属性。查看 MDN 中的属性列表。它只有值和占位符。
其次,如果要向数据集中添加新城市,必须将 city-object 合并到数组中,而不是替换它。
setDataSet(currentDataSet => {
return [...currentDataSet, city]
})
我猜是因为你在使用不受控制的组件。
如果您希望输入值反映状态变化,您需要使用该值而不是默认值,并且您可能还需要一个 onChange 处理程序。
<input value={city.City} />