Can't understand what I'm doing wrong here. I have a very simple object state:
const [itemInput, setItemInput] = useState({
userId: userId,
objectId: id,
title: "",
description: "",
createdAt: new Date().getTime().toString(),
})
Then, I have an input that changes the title field:
const onChange = (e) => {
setItemInput((prevState) => ({
...prevState,
[e.target.name]: e.target.value,
}));
};
And this is how onChange is used:
<input
type="text"
className="item-description-input"
placeholder="Add description..."
name="title"
value={itemInput.title}
onChange={onChange}
/>
GraphQL endpoint:
export const CREATE_ITEM = gql`
mutation createItem($itemInput: ItemInput!) {
createItem(itemInput: $itemInput) {
userId
objectId
title
description
createdAt
}
}
`;
Submit function:
const onAddItemClick = (e) => {
e.preventDefault();
createItem({
variables: {
itemInput: itemInput,
},
}).then((res) => {
console.log(res);
});
};
When submitting, I get:
message: "Variable "$itemInput" got invalid value { title: "ddd" }; Field "userId" of required type "MongoId!" was not provided."
And this error is repeated for all the remaining fields but title.
If I console.log(itemInput) when the functional component is loaded, I get the initial state of the object. However if I add console.log(itemInput) after onChange, I get only {title: "some_added_text"}. onChange removes the other fields from the object, and, on submit, my graphQL endpoint returns an error that the other fields are not provided. This is very frustrating, as I seem to be doing everything correctly.
UPD: Added the components. Object component gets the list of objects. Each Object has Items. The problematic code is in the Items component when I want to add a new Item to that Object.
Object (parent) component:
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;
Item (child) component:
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;
What am I missing here?