useState只修改接口的一个字段

Modify only one field of the interface with the useState

我定义了这个接口并进行了初始化:

 interface userInterface {
  email:string
  name:string
  last_name:string
 }

 const [userData, setUserData] = useState <userInterface> ({
  email:"",
  name:"",
  last_name:"",
  
 })

那么如果您只想更改名称。应该如何使用 setUserData 来完成?

也就是说,我想保留电子邮件和last_name,但只修改名称

简单的例子:

setUserData((prev) => ({ ...prev, name: 'Name you want' }));

const { useState } = React;

const DemoComponent = () => {
  const [userData, setUserData] = useState({
    email: "",
    name: "",
    last_name: ""
  });

  const handleBtnOnClick = (name) => {
    setUserData((prev) => ({ ...prev, name: name }));
  };

  return (
    <div>
      <button
        onClick={() => {
          handleBtnOnClick("Jay");
        }}
      >
        Jay
      </button>
      <button
        onClick={() => {
          handleBtnOnClick("Andy");
        }}
      >
        Andy
      </button>
      <button
        onClick={() => {
          handleBtnOnClick("Olivia");
        }}
      >
        Olivia
      </button>
      <div>{JSON.stringify(userData, null, "\t")}</div>
    </div>
  );
}

ReactDOM.render(
  <DemoComponent />,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

@Jay Lu 说的对

我想注意几件事。

打字稿接口

  • 接口名称应使用 PascalCasing
  • 键名应使用驼峰式
  • 在适当的地方优先使用实用程序类型
  • [optional] 接口名称应以大写“I”开头
    • 这曾经是一个惯例,现在越来越多的人正在远离它。您的选择

界面更新:1) 命名约定

interface UserInterface {
  email:string
  name:string
  lastName:string
}

接下来我们要做的是使用实用程序类型来简化代码的冗长。

界面更新:2) 实用程序类型 我们实际上会将此接口更改为一种类型,以便轻松使用实用程序类型 Record.

type UserInterface = Record<"email" | "name" | "lastName", string>;

至于你的组件,你没有在那里提供太多细节,所以我将提供有关设置状态的详细信息。

功能组件:更新状态

确定您需要“订阅”更改的变量或数据非常重要。例如,如果电子邮件和姓名是静态的(永不更改),则无需将它们置于会导致状态变量默认为空字符串的状态:

const [userData, setUserData] = useState("");

如果不是这种情况并且您确实需要更新和管理电子邮件、姓名和姓氏更新状态很简单:使用更新后的值传播现有状态。您可以使用从 useState 返回的元组中提供的 setter 函数来执行此操作。在本例中为 setUserData。 setter 函数采用与默认 相同类型的值,它可以接受回调函数,它为您提供 current 状态值。这对于更新状态对象变量非常强大且非常有用。对于您的情况,我们有:

setUserData((previous) => ({...previous, name: "Updated name value"});

这里发生了什么?如果我们向 setUserData 传递回调,它会为我们提供“先前”状态。第一次调用此函数时,"previous" 是:

{
  email: "",
  name: "",
  lastName: ""
}

我们正在获取该值并将其分布在具有更新值的 new 对象中。这与 Object.assign 相同。如果您传播对象中已存在的键,它将被替换。在我们传播我们的状态对象之后看起来像:

{
  email: "", // didn't change because we didn't pass a new value
  lastName: "", // didn't change because we didn't pass a new value
  name: "Updated name value" // changed because we passed a new value
}

这意味着,如果您想更新电子邮件,只需执行以下操作即可:

setUserData((previous) => ({...previous, email: "hello@world.com"});

现在您的状态对象将是:

{
  email: "hello@world.com",
  lastName: "",
  name: "Updated name value"
}

如果您再次使用回调调用 setUserData,则之前的值将是上面的那个对象。

如果您想将其设置回原始值,您可以在不使用回调的情况下更新整个状态。为什么?因为我们不需要保留任何值,因为我们想覆盖它:

setUserData({ email: "", lastName: "", name: ""});

虽然有一点改进。如果我们决定在某个时候我们想要“重置为默认值”,我们应该将默认值存储在一个变量中并重新使用它。不是 100% 必要,但它可能是一个很好的更新,特别是如果你有一个复杂的组件。

关于 Typescript 强大功能的快速说明 如果您尝试使用之前未定义的新密钥更新状态,假设“helloWorld”打字稿会给您一个错误,因为“helloWorld”未在您的 UserData 类型中定义。

希望@Jay Lu 的回答和其中的一些信息有所帮助。如果您提供更多详细信息,我们可能会提供更多指导。