[英]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.