我想我在 ReactJS 中遗漏了一些关于 useState() 钩子的相当基本的东西?
I think I'm missing something fairly basic about useState() hook in ReactJS?
我正在尝试使用 useState() 将相同的对象数组添加到两个不同的有状态变量,这样我就可以允许用户对第一个应用更改,然后放弃更改并使用第二个恢复到通过选择一个按钮的开始状态。我是 React 的新手,结果 没有 像预期的那样工作!当用户输入更改时,出于某种原因,这些更改同时应用于 both,因此现在没有任何内容保留开始状态,如果用户选择 'Discard Changes'按钮。
我已将代码简化为以下示例:
import {useState} from 'react';
const budgetData =
[
{ index: 0, category: 'Housing', item: 'Mortgage', amount: 650.99 },
{ index: 1, category: 'Housing', item: 'Insurance', amount: 275.50 },
{ index: 2, category: 'Utilities', item: 'Hydro', amount: 70.00 }
];
function UpdateBudget() {
const backup = budgetData;
const [data, setData ] = useState(budgetData);
const [dataBackup ] = useState(backup);
const handleChange = ( (e, row) => {
let selectedData = [...data];
const {name, value} = e.target;
selectedData[row][name] = value;
setData(selectedData);
});
const handleReset = ( (e) => {
setData(dataBackup);
});
return (
<div>
<table>
<thead>
<tr>
<th>Category</th> <th>Item</th> <th>Amount</th>
</tr>
</thead>
<tbody>
{ data.map( (row) => (
<tr key={row.index}>
<td> <input value={row.category} name="category" onChange={(e) => handleChange(e, row.index)}/> </td>
<td> <input value={row.item } name="item" onChange={(e) => handleChange(e, row.index)}/> </td>
<td> <input value={row.amount } name="amount" onChange={(e) => handleChange(e, row.index)}/> </td>
</tr>
))
}
</tbody>
</table>
<div>
<button onClick={ (e) => handleReset (e)}> Discard Changes </button>
</div>
<div style={{ marginTop: 20, fontSize: 10 }}> * data {data.length} * {JSON.stringify(data)} </div>
<div style={{ marginTop: 20, fontSize: 10 }}> * dataBackup {dataBackup.length} * {JSON.stringify(dataBackup)} </div>
</div>
);
}
感谢有人指点我,指出我在这里缺少的东西!
我怀疑是因为克隆数组不会创建子元素的副本。 selectedData[row][name]
这仍然引用相同的值,这是一个 JS 怪癖。
const budgetData = [
["foo"],
["bar"],
["baz"],
]
const backup = budgetData
const clonedData = [...backup]
clonedData[0][0] = "abc"
console.log(backup) // backup data is mutated
看看 lodash cloneDeep
,它也会复制子值 https://lodash.com/docs/4.17.15#cloneDeep
const budgetData = [
["foo"],
["bar"],
["baz"],
]
const backup = budgetData
const clonedData = _.cloneDeep(backup)
clonedData[0][0] = "abc"
console.log(backup) // backup data is not mutated
console.log(clonedData) // cloned data holds the changes
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
另外,我认为您不需要第二个状态,因为您没有改变它。你可以放弃这个 const [dataBackup ] = useState(backup)
并只使用 backup
我正在尝试使用 useState() 将相同的对象数组添加到两个不同的有状态变量,这样我就可以允许用户对第一个应用更改,然后放弃更改并使用第二个恢复到通过选择一个按钮的开始状态。我是 React 的新手,结果 没有 像预期的那样工作!当用户输入更改时,出于某种原因,这些更改同时应用于 both,因此现在没有任何内容保留开始状态,如果用户选择 'Discard Changes'按钮。
我已将代码简化为以下示例:
import {useState} from 'react';
const budgetData =
[
{ index: 0, category: 'Housing', item: 'Mortgage', amount: 650.99 },
{ index: 1, category: 'Housing', item: 'Insurance', amount: 275.50 },
{ index: 2, category: 'Utilities', item: 'Hydro', amount: 70.00 }
];
function UpdateBudget() {
const backup = budgetData;
const [data, setData ] = useState(budgetData);
const [dataBackup ] = useState(backup);
const handleChange = ( (e, row) => {
let selectedData = [...data];
const {name, value} = e.target;
selectedData[row][name] = value;
setData(selectedData);
});
const handleReset = ( (e) => {
setData(dataBackup);
});
return (
<div>
<table>
<thead>
<tr>
<th>Category</th> <th>Item</th> <th>Amount</th>
</tr>
</thead>
<tbody>
{ data.map( (row) => (
<tr key={row.index}>
<td> <input value={row.category} name="category" onChange={(e) => handleChange(e, row.index)}/> </td>
<td> <input value={row.item } name="item" onChange={(e) => handleChange(e, row.index)}/> </td>
<td> <input value={row.amount } name="amount" onChange={(e) => handleChange(e, row.index)}/> </td>
</tr>
))
}
</tbody>
</table>
<div>
<button onClick={ (e) => handleReset (e)}> Discard Changes </button>
</div>
<div style={{ marginTop: 20, fontSize: 10 }}> * data {data.length} * {JSON.stringify(data)} </div>
<div style={{ marginTop: 20, fontSize: 10 }}> * dataBackup {dataBackup.length} * {JSON.stringify(dataBackup)} </div>
</div>
);
}
感谢有人指点我,指出我在这里缺少的东西!
我怀疑是因为克隆数组不会创建子元素的副本。 selectedData[row][name]
这仍然引用相同的值,这是一个 JS 怪癖。
const budgetData = [
["foo"],
["bar"],
["baz"],
]
const backup = budgetData
const clonedData = [...backup]
clonedData[0][0] = "abc"
console.log(backup) // backup data is mutated
看看 lodash cloneDeep
,它也会复制子值 https://lodash.com/docs/4.17.15#cloneDeep
const budgetData = [
["foo"],
["bar"],
["baz"],
]
const backup = budgetData
const clonedData = _.cloneDeep(backup)
clonedData[0][0] = "abc"
console.log(backup) // backup data is not mutated
console.log(clonedData) // cloned data holds the changes
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
另外,我认为您不需要第二个状态,因为您没有改变它。你可以放弃这个 const [dataBackup ] = useState(backup)
并只使用 backup