Javascript useState()钩子在设置新值时从对象中删除字段
我不明白我做错了什么。我有一个非常简单的对象状态:Javascript useState()钩子在设置新值时从对象中删除字段,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我不明白我做错了什么。我有一个非常简单的对象状态: const [itemInput, setItemInput] = useState({ userId: userId, objectId: id, title: "", description: "", createdAt: new Date().getTime().toString(), }) 然后,我有一个更改标题字段的输入: const onChang
const [itemInput, setItemInput] = useState({
userId: userId,
objectId: id,
title: "",
description: "",
createdAt: new Date().getTime().toString(),
})
然后,我有一个更改标题
字段的输入:
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}
/>
提交功能:
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."
除了标题
,其余所有字段都会重复此错误
如果在加载功能组件时我console.log(itemInput)
,我将获得对象的初始状态。但是,如果我在onChange
之后添加console.log(itemInput)
,我只会得到{title:“some\u added\u text”}
。onChange从对象中删除其他字段,并且在提交时,我的graphQL端点返回一个错误,即未提供其他字段。这是非常令人沮丧的,因为我似乎做的每件事都是正确的
UPD:添加了组件<代码>对象组件获取对象列表。每个对象
都有项
。当我想向该对象添加一个新的项目时,问题代码出现在项目
组件中
对象(父)组件:
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;
import React,{useState,useReactiveVar,Fragment}来自“React”;
从“@apollo/client”导入{useStation}”;
从“../../mutations/OBJECT”导入创建对象;
从“./../cache”导入{objectsVar};
//组成部分
从“/ItemContainer”导入ItemContainer;
常量容器=({data,userId,color})=>{
常量[objectInput,setobjectInput]=useState({
标题:“,
userId:userId,
createdAt:new Date().getTime().toString(),
颜色:颜色,
});
const[createObject]=使用变异(创建对象);
const onAddClick=(e)=>{
e、 预防默认值();
createObject({
变量:{
objectInput:objectInput,
},
})。然后((res)=>{
setobjectInput({
标题:“,
userId:userId,
createdAt:new Date().getTime().toString(),
颜色:颜色,
});
});
};
//这个很好用!!
const onChange=(e)=>{
setobjectInput({…objectInput[e.target.name]:e.target.value});
};
objectsVar(数据);
const objects=useReactiveVar(objectsVar);
返回(
添加对象
{objects&&objects.getAllObjects.length==0(
没有物体
) : (
{对象&&
objects.getAllActiviesWimlines.map({u id,title,items})=>(
))}
)}
);
};
导出默认容器;
项目(子)组件:
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;
import React,{useState,Fragment}来自“React”;
从“./Item/ItemContainer”导入ItemContainer;
从“@apollo/client”导入{useStation}”;
从“./../translations/ITEM”导入{CREATE_ITEM};
const ItemContainer=({id,title,items,userId})=>{
常量[itemInput,setItemInput]=useState({
userId:userId,
对象:id,
标题:“初始状态”,
描述:“测试描述”,
createdAt:new Date().getTime().toString(),
});
//这不行!
const onChange=(e)=>{
常量{name,value}=e.target;
setItemInput({
…项目输入,
[名称]:值,
});
};
const[createItem]=使用变异(创建_项);
常量onAddItemClick=(e)=>{
e、 预防默认值();
createItem({
变量:{
itemInput:itemInput,
},
})。然后((res)=>{
setItemInput({
userId:userId,
对象:id,
标题:“,
说明:“,
createdAt:new Date().getTime().toString(),
});
控制台日志(res);
});
};
常量newItemInput=(
添加项
);
const itemContent=(
{项目&&
items.getObjectItems.map(({u id,title})=>(
))}
);
返回(
{newItemInput}
{itemContent}
);
};
导出默认ItemContainer;
我这里缺少什么?因为您在更新函数中访问了e.target.name
和e.target.value
,所以不会立即对它们求值,而且在求值时,合成事件对象已被重用。如果要保持代码的其余部分不变,可以通过在onChange
的开头调用e.persist()
来修复它,或者从事件中复制相关信息:
const onChange = (e) => {
const {name, value} = e.target
setItemInput((prevState) => ({
...prevState,
[name]: value,
}));
};
或者,您可以放弃update函数,直接设置状态(在另一个被删除的答案中也建议):
谢谢你的回答。我在const{name,value}之前添加了e.persist(),结果仍然相同。在代码中尝试了不使用e.persist(),但仍然没有成功。请注意,这个答案将不再像以前那样适用于React>=v17。我使用的是17.0.1。@oblosys的两个版本产生相同的结果。问题是,相同的代码在父组件中工作,我真的很困惑。好的一点,这个问题不会再发生了。但是,如果两种解决方案都不能解决原来的问题,那么可能会出现其他问题。如果看不到整个组件(最好是剥离),很难说问题是什么。为了修补组件,在呈现中包含{JSON.stringify(itemInput)}
可能会很有帮助,这样您就可以很容易地看到状态。您能提供一个?展示整个组件以及如何在其中使用这些功能将为那些试图解决您的问题的人提供一些有价值的见解。此外,如果您使用eslint,我强烈建议您立即安装它,这可能会暴露您的问题,因为听起来您只是在某个地方缺少依赖项。此外@PatrickRoberts:您的示例很好:(顺便说一句:您应该使用currentTarget
,而不是target
)。你能提供一个真实的例子吗?@PatrickRoberts添加了组件SetItemInput({