在 React select 中使用枚举

Nar*_*esh 6 enums typescript reactjs

我想使用以下枚举在 React 中显示一个下拉列表。这个想法是为了防止使用随机字符串作为我的<select>. 键应限制为Stooges.larry,Stooges.curlyStooges.moe

const Stooges = {
  larry: "Larry Fine",
  curly: "Curly Howard",
  moe: "Moe Howard"
};
Run Code Online (Sandbox Code Playgroud)

这是我选择的代码,它工作得很好:

<select value={stooge} onChange={handleChange}>
  {Object.keys(Stooges).map(key => (
    <option key={key} value={key}>
      {Stooges[key]}
    </option>
  ))}
</select>
Run Code Online (Sandbox Code Playgroud)

当我尝试设置下拉列表的初始值时出现问题 - 我必须使用硬编码键:

const [stooge, setStooge] = React.useState('larry');
Run Code Online (Sandbox Code Playgroud)

我可以通过选择第一个键来软化这一点:

const keys = Object.keys(Stooges);
const [stooge, setStooge] = React.useState(keys[0]);
Run Code Online (Sandbox Code Playgroud)

然而,这仍然感觉不对。我不知道key[0]我在挑选谁。

在这个用例中有没有更好的方法来处理枚举?我在 TypeScript 中尝试过字符串枚举,但它们有同样的问题:

enum Stooges {
  larry = "Larry Fine",
  curly = "Curly Howard",
  moe = "Moe Howard"
}
Run Code Online (Sandbox Code Playgroud)

在此处查看我的 CodeSandbox 。

小智 9

对于枚举Animals

enum Animal{
  Cat= "Cat",
  Dog= "Dog",
  Hamster= "Hamster"
}
Run Code Online (Sandbox Code Playgroud)

我们可以定义一个通用函数getEnumKeys,它获取枚举的键数组:

// Inspired from https://github.com/microsoft/TypeScript/issues/30611#issuecomment-570773496
function getEnumKeys<
    T extends string,
    TEnumValue extends string | number,
>(enumVariable: { [key in T]: TEnumValue }) {
    return Object.keys(enumVariable) as Array<T>;
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以映射select 中函数Animal返回的键列表。getEnumKeys

import React from "react";

enum Animal {
  Cat = "Cat",
  Dog = "Dog",
  Hamster = "Hamster"
}

export default function App() {
  const [currentAnimal, setCurrentAnimal] = React.useState<Animal>(Animal.Cat);
  return (
    <select
      value={currentAnimal}
      onChange={(e) => {
        setCurrentAnimal(Animal[e.target.value as keyof typeof Animal]);
      }}
    >
      {getEnumKeys(Animal).map((key, index) => (
        <option key={index} value={Animal[key]}>
          {key}
        </option>
      ))}
    </select>
  );
}

function getEnumKeys<
   T extends string,
   TEnumValue extends string | number,
>(enumVariable: { [key in T]: TEnumValue }) {
    return Object.keys(enumVariable) as Array<T>;
}
Run Code Online (Sandbox Code Playgroud)

代码沙箱:https://codesandbox.io/s/unruffled-sinoussi-pr7dpf? file=/src/App.tsx:0-600

  • 除非我将 `&lt;T&gt;` 更改为 `&lt;T extends Object&gt;`,否则出现打字稿错误 (4认同)

Nar*_*esh 2

由于缺乏更好的解决方案,我采取了以下方法。我至少能够通过名称选择正确的枚举Stooges.larry.id::

const Stooges = {
  larry: {
    id: "larry",
    name: "Larry Fine"
  },
  curly: {
    id: "curly",
    name: "Curly Howard"
  },
  moe: {
    id: "moe",
    name: "Moe Howard"
  }
};

function App() {
  const [stooge, setStooge] = React.useState(Stooges.larry.id);

  const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
    setStooge(event.target.value);
  };

  return (
    <div className="App">
      <select value={stooge} onChange={handleChange}>
        {Object.keys(Stooges).map(key => (
          <option key={key} value={key}>
            {Stooges[key].name}
          </option>
        ))}
      </select>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

这是新的 CodeSandbox:https ://codesandbox.io/embed/wqj2q94o2k