React State在迭代时使用基于id的对象更新嵌套数组



我对填充的对象/数组有一个反应状态,但后来我想编辑文本输入和对象上的相关字段,直到现在我还没有找到解决方案。

这就是我的状态,例如:

const [data, setData] = useState({
working_hours: [
{
id: 1,
description: 'Random Text',
price: 100,
},
{
id: 2,
description: 'Text Random',
price: 100,
},
]
});

这是我的Jsx:

{data.working_hours.map(item => 
<>
<input type={text} value={item.description}
onChange={(e) => handleChange(e)} />
<input type={text} value={item.price}
onChange={(e) => handleChange(e)} />
</>
)}

以下是我尝试过的:

function handleChange(e){
const value = e.target.value;
setData({...data, [...data.working_hours, e.target.value]})
}

您需要将其他参数作为要更新的项目ID和属性名称传递给handleChange,因为如果没有这些参数,您将无法确定要动态更新的属性。通过这种方式,您可以对多个输入使用相同的handleChange
请参阅以下代码-

function handleChange(e, itemId, property) {
const value = e.target.value;
//copying data to temp variable so that we do not directly mutate original state
const tempWorkingHours = [...data.working_hours];
//findIndex to find location of item we need to update
let index = tempWorkingHours.findIndex(item => item.id == itemId);
// -1 check to see if we found that object in working hours
if(index != -1){
tempWorkingHours[index] = {
...tempWorkingHours[index], //keeping existing values in object
[property]: value  //here property can be "price" or "description"
}
}

setData({ ...data, working_hours: tempWorkingHours })
}
{
data.working_hours.map(item =>
<>
<input type={text} value={item.description}
onChange={(e) => handleChange(e, item.id, "description")} />
<input type={text} value={item.price}
onChange={(e) => handleChange(e, item.id, "price")} />
</>
)
}

当您想要更新嵌套数组中对象的状态时,您必须识别这些对象和您想要更新的属性。因此,您的处理程序应该是这样的。

function handleChange(index, property, value){
// ...
}

只有当您向setData函数传递一个新对象时,它才会触发一个重新应答器。因此,您应该创建一个副本。

function handleChange(index, property, value) {
const new_working_hours = [...data.working_hours]; // copy the array
const new_working_hour = { ...data.working_hours[index] }; // copy the array item to change
new_working_hour[property] = value; // set the new value
new_working_hours[index] = new_working_hour; // assign the new item to the copied array
setData({ working_hours: new_working_hours }); // return a new data object
}

下面是一个工作示例。单击下面的Run code snippet

const { useState } = React;
const App = () => {
const [data, setData] = useState(initialState);
function handleChange(index, property, value) {
const new_working_hours = [...data.working_hours]; // copy the array
const new_working_hour = { ...data.working_hours[index] }; // copy the array item to change
new_working_hour[property] = value; // set the new value
new_working_hours[index] = new_working_hour; // assign the new item to the copied array
setData({ working_hours: new_working_hours }); // return a new data object
}
return data.working_hours.map((item, index) => (
<div>
<input
type="text"
value={item.description}
onChange={(e) => handleChange(index, "description", e.target.value)}
/>
<input
type="text"
value={item.price}
onChange={(e) => handleChange(index, "price", e.target.value)}
/>
</div>
));
};

const initialState = {
working_hours: [
{
id: 1,
description: "Random Text",
price: 100
},
{
id: 2,
description: "Text Random",
price: 100
}
]
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

function handleChange(e){
const value = e.target.value;
const newData = {
...data,
working_hours: [
...(data?.working_hours ? data.working_hours : {}),
value
]
};
setData(newData);
}

这是一个模拟

let data = {
working_hours: [
{
id: 1,
field: "test",
}
],
};
function handleChange(e){
const value = e.target.value;
const newData = {
...data,
working_hours: [
...(data?.working_hours ? data.working_hours : {}),
value
]
};
console.log('newData', newData);
}
const event = {
target: {
value: { id: 2, field: "test2" },
}
};
handleChange(event);

问题是您缺少指示要更新哪个对象的部分,您可以通过传递数组的索引或对象的id来实现这一点。例如:

function handleChange(e){
const value = e.target.value;
const tempWorkingHours = data.working_hours.map((item) => { 
if (item.id === value.id) {
return {
...item,
price: value
} 
}
return item;
}
setData({...data, working_hours: tempWorkingHours })
}

通过这种方式,您可以使用映射在数组上循环,并找到要更改的项(但通过保存数据副本的临时变量来避免状态发生变化(。您还可以将索引传递给句柄更改函数:

{data.working_hours.map((item, index) => 
<>
<input type={text} value={item.description}
onChange={(e) => handleChange(e)} />
<input type={text} value={item.price}
onChange={(e,index) => handleChange(e, index)} />
</>
)}

然后在handleChange中使用索引访问相关索引以更改数组。如果你想让我通过修改你的代码来解释更多,请告诉我,但我认为我上面用id解决方案解释的方式很好。

编辑-索引版本:

function handleChange(e, index) {  
const value = e.target.value; 
const tempWorkingHours = [...data.working_hours];  
tempWorkingHours[index].price = value;  
setData({...data, working_hours: tempWorkingHours});
}

修正了第一个例子,返回移动到if语句之外,以防它不是我们想要修改的相关id。

阅读react官方文档中有关表格的更多信息:https://reactjs.org/docs/forms.html是否使用函数组件来获取点并不重要,这是一样的。只有您更新状态的方式是useState

class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};

this.handleInputChange = this.handleInputChange.bind(this);
}

handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;

this.setState({
[name]: value
});
}

render() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}

更改elements

{data.working_hours.map(item => 
<>
<input name='description' type={text} value={item.description}
onChange={(e) => handleChange(e,item.id)} />
<input name='price' type={text} value={item.price}
onChange={(e) => handleChange(e,item.id)} />
</>
)}

更改handleChange


function handleChange(e,id){
const value = e.target.value;
const name= e.target.name;
var dataitemIndex = data.working_hours.findIndex(x=>x.id == id);
data.working_hours[dataitemIndex] = {...data.working_hours[dataitemIndex],[event.target.name]: event.target.value};
setData(data);
}

最新更新