簡體   English   中英

useState() 鈎子在設置新值時從 object 中刪除字段

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM