reactjs 使用通用组件的React组合

w6mmgewl  于 2023-03-29  发布在  React
关注(0)|答案(1)|浏览(118)

我正在尝试使用组件组合来设计一个自动完成组件,其接口如下所示:

<Autocomplete.Root value={currentValue} onChange={handleChange}>
    <Autocomplete.Input />
    <Autocomplete.Dropdown>
        {options.map((option) => (
            <Autocomplete.Option value={option.value}>{option.label}</Autocomplete.Option>
        )}
    </Autocomplete.Dropdown>
</Autocomplete.Root>

这些组件需要类型参数T(值的类型):

  • Autocomplete.Root
  • Autocomplete.Input
  • Autocomplete.Option

目前,它们都指定了自己的类型参数,但没有办法检查它们是否彼此一致,因此目前可能有如下内容:

<Autocomplete.Root value={123} onChange={handleChange}>
    <Autocomplete.Input />
    <Autocomplete.Dropdown>
        <Autocomplete.Option value="Some string value">{option.label}</Autocomplete.Option>
    </Autocomplete.Dropdown>
</Autocomplete.Root>

这将产生可怕的运行时错误。
有没有办法让所有这些组件使用相同的类型参数?

我尝试了什么

例如,我尝试只导出一个类Autocomplete<T>,如下所示:

export class Autocomplete<T> {
    public Root = AutocompleteRoot<T>;
    public Input = AutocompleteInput<T>;
    public Dropdown = AutocompleteDropdown;
    public Option = AutocompleteOption<T>;
}

这样你至少可以用途:

type StringAutocomplete = Autocomplete<string>;

但React不允许在JSX中以这种方式使用类。

ttcibm8c

ttcibm8c1#

确保所有组件使用相同类型参数的一种方法是为每个组件的props使用泛型接口。
下面是一个如何为每个组件定义通用接口的示例:

interface AutocompleteRootProps<T> {
value: T;
onChange: (value: T) => void;
}

interface AutocompleteInputProps<T> {
  value: T;
  onChange: (value: T) => void;
}

interface AutocompleteDropdownProps {
  children: React.ReactNode;
}

interface AutocompleteOptionProps<T> {
  value: T;
  children: React.ReactNode;
}

然后,您可以使用适当的通用接口定义每个组件:

function AutocompleteRoot<T>(props: AutocompleteRootProps<T>) {
  // ...
}

function AutocompleteInput<T>(props: AutocompleteInputProps<T>) {
  // ...
}

function AutocompleteDropdown(props: AutocompleteDropdownProps) {
  // ...
}

function AutocompleteOption<T>(props: AutocompleteOptionProps<T>) {
  // ...
}

最后,你可以将Autocomplete组件定义为一个高阶组件,它接受类型参数T,并使用正确的props渲染其他组件:

interface AutocompleteProps<T> {
  value: T;
  onChange: (value: T) => void;
  options: { value: T; label: string }[];
}

function Autocomplete<T>(props: AutocompleteProps<T>) {
  const { value, onChange, options } = props;

  return (
    <AutocompleteRoot value={value} onChange={onChange}>
      <AutocompleteInput value={value} onChange={onChange} />
      <AutocompleteDropdown>
        {options.map((option) => (
          <AutocompleteOption key={option.value} value={option.value}>
            {option.label}
          </AutocompleteOption>
        ))}
      </AutocompleteDropdown>
    </AutocompleteRoot>
  );
}

这种方法确保所有组件使用相同的类型参数T,并在使用组件时提供类型安全性。例如,如果您尝试为Autocomplete.Root的值属性使用错误类型的值,则会在编译时获得TypeScript错误,而不是运行时错误。

相关问题