学习一个React Typescript变更处理程序

41 阅读1分钟

在React与Typescript中,你可能会被诱惑为组件中的每个字段卷起单独的变化处理程序。今天我将告诉你如何避免这种多余的工作,只写一个变化处理程序

一个简单的用例

这里有一个简单的用例:我们有一个React的表单,有两个文本输入和一个复选框输入。这些输入将填充一个User 对象,它将有以下类型。

type User = {
  name: string;
  age: number;
  admin: boolean;
};

让我们看看这在React组件的上下文中会是什么样子。我们将使用useState 钩子来维护用户对象的内部状态。

import React, { useState } from 'react';

type User = {
  name: string;
  age: number | null;
  admin: boolean;
};

const defaultUser: User = {
  name: '',
  age: null,
  admin: false,
};

function App() {
  const [user, setUser] = useState(defaultUser);

  return (
    <div>
      <input value={user.name} />
      <input value={user.age || ''} />
      <input type="checkbox" checked={user.admin} />
    </div>
  );
}

处理变化

但如何处理每个属性的变化呢?好吧,我们可以为每个输入创建一个不同的变化处理程序,但这将是多余的。让我们创建一个单一的onUserChange ,为每个输入设置正确的道具。

import React, { useState } from 'react';

type User = {
  name: string;
  age: number | null;
  admin: boolean;
};

const defaultUser: User = {
  name: '',
  age: null,
  admin: false,
};

function App() {
  const [user, setUser] = useState(defaultUser);

  const onUserChange = <P extends keyof User>(prop: P, value: User[P]) => {
    setUser({ ...user, [prop]: value });
  };

  return (
    <div>
      <input
        value={user.name}
        onChange={(e) => {
          onUserChange('name', e.target.value);
        }}
      />
      <input
        value={user.age || ''}
        onChange={(e) => {
          onUserChange('age', parseInt(e.target.value));
        }}
      />
      <input
        type="checkbox"
        checked={user.admin}
        onChange={() => {
          onUserChange('admin', !user.admin);
        }}
      />
    </div>
  );
}

这里的秘诀是我们在onUserChange 处理程序中使用的泛型。通过说prop 的类型是P ,其中P extends keyof User ,我们可以根据第一个参数对onUserChange 的第二个参数进行类型检查。然后,当我们setUser ,typescript编译器就会对我们的类型表示满意。