[英]useState() hook removes fields from the object when setting new value
无法理解我在这里做错了什么。 我有一个非常简单的 object state:
const [itemInput, setItemInput] = useState({
userId: userId,
objectId: id,
title: "",
description: "",
createdAt: new Date().getTime().toString(),
})
然后,我有一个更改title
字段的输入:
const onChange = (e) => {
setItemInput((prevState) => ({
...prevState,
[e.target.name]: e.target.value,
}));
};
这就是onChange
的使用方式:
<input
type="text"
className="item-description-input"
placeholder="Add description..."
name="title"
value={itemInput.title}
onChange={onChange}
/>
GraphQL 端点:
export const CREATE_ITEM = gql`
mutation createItem($itemInput: ItemInput!) {
createItem(itemInput: $itemInput) {
userId
objectId
title
description
createdAt
}
}
`;
提交 function:
const onAddItemClick = (e) => {
e.preventDefault();
createItem({
variables: {
itemInput: itemInput,
},
}).then((res) => {
console.log(res);
});
};
提交时,我得到:
message: "Variable "$itemInput" got invalid value { title: "ddd" }; Field "userId" of required type "MongoId!" was not provided."
并且除了title
之外的所有剩余字段都会重复此错误。
如果我在加载功能组件时使用console.log(itemInput)
,我会得到 object 的初始 state。 但是,如果我在onChange
之后添加console.log(itemInput)
,我只会得到{title: "some_added_text"}
。 onChange 从 object 中删除其他字段,并且在提交时,我的 graphQL 端点返回未提供其他字段的错误。 这非常令人沮丧,因为我似乎做的一切都是正确的。
UPD:添加了组件。 Object
组件获取对象列表。 每个Object
都有Items
。 当我想向该Object
添加新Item
时,有问题的代码位于Items
组件中。
Object(父)组件:
import React, { useState, useReactiveVar, Fragment } from "react";
import { useMutation } from "@apollo/client";
import CREATE_OBJECT from "../../mutations/Object";
import { objectsVar } from "../../cache";
//Components
import ItemContainer from "./ItemContainer";
const Container = ({ data, userId, color }) => {
const [objectInput, setobjectInput] = useState({
title: "",
userId: userId,
createdAt: new Date().getTime().toString(),
color: color,
});
const [createObject] = useMutation(CREATE_OBJECT);
const onAddClick = (e) => {
e.preventDefault();
createObject({
variables: {
objectInput: objectInput,
},
}).then((res) => {
setobjectInput({
title: "",
userId: userId,
createdAt: new Date().getTime().toString(),
color: color,
});
});
};
// This works perfectly fine!!
const onChange = (e) => {
setobjectInput({ ...objectInput, [e.target.name]: e.target.value });
};
objectsVar(data);
const objects = useReactiveVar(objectsVar);
return (
<div>
<div>
<input
type="text"
placeholder="Add description..."
name="title"
value={objectInput.title}
onChange={onChange}
/>
</div>
<div onClick={onAddClick}>Add object</div>
{objects && objects.getAllObjects.length === 0 ? (
<p>No objects</p>
) : (
<Fragment>
{objects &&
objects.getAllActiveSwimlines.map(({ _id, title, items }) => (
<ItemContainer key={_id} id={_id} title={title} userId={userId} items={items} />
))}
</Fragment>
)}
</div>
);
};
export default Container;
项目(子)组件:
import React, { useState, Fragment } from "react";
import ItemContainer from "../Item/ItemContainer";
import { useMutation } from "@apollo/client";
import { CREATE_ITEM } from "../../mutations/Item";
const ItemContainer = ({ id, title, items, userId }) => {
const [itemInput, setItemInput] = useState({
userId: userId,
objectId: id,
title: "initial state",
description: "test desc",
createdAt: new Date().getTime().toString(),
});
// This doesn't work!
const onChange = (e) => {
const { name, value } = e.target;
setItemInput({
...itemInput,
[name]: value,
});
};
const [createItem] = useMutation(CREATE_ITEM);
const onAddItemClick = (e) => {
e.preventDefault();
createItem({
variables: {
itemInput: itemInput,
},
}).then((res) => {
setItemInput({
userId: userId,
objectId: id,
title: "",
description: "",
createdAt: new Date().getTime().toString(),
});
console.log(res);
});
};
const newItemInput = (
<div>
<input
type="text"
placeholder="Add description..."
name="title"
value={itemInput.title}
onChange={onChange}
/>
<div onClick={onAddItemClick}>Add item</div>
</div>
);
const itemContent = (
<div>
<Fragment>
{items &&
items.getObjectItems.map(({ _id, title }) => (
<Item key={_id} id={_id} title={title} />
))}
</Fragment>
</div>
);
return (
<div>
{newItemInput}
{itemContent}
</div>
);
};
export default ItemContainer;
我在这里想念什么?
因为您在更新 function 中访问e.target.name
和e.target.value
,所以不会立即对它们进行评估,而当他们这样做时,合成事件 object 已被重用。 如果您想保持代码的 rest 不变,可以通过在onChange
开头调用e.persist()
来修复它,或者从事件中复制相关信息:
const onChange = (e) => {
const {name, value} = e.target
setItemInput((prevState) => ({
...prevState,
[name]: value,
}));
};
或者,您可以让更新 function 的 go 并直接设置 state ,(在已删除的其他答案中也建议):
const onChange = (e) => {
setItemInput({
...itemInput,
[e.target.name]: e.target.value,
});
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.