如何使这个通用组件在 TSX 中工作

问题描述 投票:0回答:1

我一直在努力解决这个组件的打字问题。它需要是通用的,但我似乎无法使它工作:

import { clsx } from 'clsx';
import { useCombobox } from 'downshift';
import type { ForwardedRef, ReactNode } from 'react';
import { forwardRef } from 'react';

import { Input } from '../../atoms/Input/Input';

import './Combobox.css';
import { ComboboxProvider } from './ComboboxContext';
import { ComboboxList } from './ComboboxList';
import { ComboboxListItem } from './ComboboxListItem';
import type { ComboboxProps } from './types';

/**
 * ComboBox
 *
 * @description A component with a dropdown, search and filter functionality
 *
 * @example
 * <Combobox>
 *  <Combobox.Prefix>
 *    <Search />
 *  </Combobox.Prefix>
 *  <Combobox.List>
 *    <Combobox.Item>
 *      <Item />
 *    </Combobox.Item>
 *    <Combobox.Item>
 *      <Item />
 *    </Combobox.Item>
 *    <Combobox.Item>
 *      <Item />
 *    </Combobox.Item>
 *    <Combobox.Item>
 *      <Item />
 *    </Combobox.Item>
 *  </Combobox.List>
 *  <Combobox.Suffix>
 *    <Close />
 *  </Combobox.Suffix>
 * </Combobox>
 */

const Combobox = forwardRef(
  <Item,>(
    { placeholder, name, id, defaultValue, className, children, ...props }: ComboboxProps<Item>,
    ref: ForwardedRef<HTMLInputElement>,
  ) => {
    const { getInputProps, ...rest } = useCombobox<Item>(props);

    return (
      <Input
        {...getInputProps({ name, id, placeholder, defaultValue, ref })}
        className={clsx('combobox', className)}
      >
        <ComboboxProvider {...rest}>{children}</ComboboxProvider>
      </Input>
    );
  },
);

const CompoundCombobox = <Item,>() =>
  Object.assign(Combobox<Item>, {
    Prefix: Input.Prefix,
    Suffix: Input.Suffix,
    List: ComboboxList,
    Item: ComboboxListItem,
  });

export { CompoundCombobox as Combobox };

这会在该行上产生以下错误(更具体地说是在通用错误上):

Object.assign(Combobox<Item>, {

类型“ForwardRefExoticComponent & UseComboboxProps & RefAttributes>”没有适用类型参数列表的签名。

这些是 ComboboxProps:

type ComboboxProps<Item> = Pick<
  InputProps,
  'className' | 'children' | 'placeholder' | 'defaultValue' | 'name' | 'id'
> &
  UseComboboxProps<Item>;

我希望能够像这样使用它:

<Combobox<ComboboxItemType>
      items={items}
      placeholder="Combobox"
      id="combobox"
      name="combobox"
      itemToString={itemToString}
      onInputValueChange={({ inputValue }) => {
        items.filter((el) => filter(el, inputValue));
      }}
    >
      <Combobox.Prefix>
        <Search />
      </Combobox.Prefix>
      <Combobox.List>
        {items.map((item, index) => (
          <Combobox.Item key={index} index={index} item={item}>
            <div
              style={{
                display: 'flex',
                flexDirection: 'row',
                justifyContent: 'space-between',
                width: '100%',
              }}
            >
              <span>{item.title}</span>
              <span style={{ color: 'var(--neutral-800)' }}>{item.category}</span>
            </div>
          </Combobox.Item>
        ))}
      </Combobox.List>
    </Combobox>
reactjs typescript generics combobox
1个回答
0
投票

两个最重要的问题:

  1. 使
    forwardRef
    变得通用是出了名的烦人,你必须跳舞才能让它发挥作用。请参阅此答案
  2. 你的
    CompoundCombobox
    不必要是一个函数。您只想将这些属性添加到组件上,不需要函数包装器。您还引用了类型
    Combobox<Item>
    作为
    Object.assign
    第一个参数中的值。你只想要
    Combobox
    在那里。
type ComboboxType = <Item>(
  props: ComboboxProps<Item> & React.RefAttributes<HTMLInputElement>,
) => React.ReactElement | null;

const Combobox: ComboboxType = forwardRef((props, ref) => {
  const { placeholder, name, id, defaultValue, className, children, ...rest } =
    props;
  const { getInputProps, ...others } = useCombobox<Item>(props);

  return (
    <Input
      {...getInputProps({ name, id, placeholder, defaultValue, ref })}
      className={clsx("combobox", className)}
    >
      <ComboboxProvider {...others}>{children}</ComboboxProvider>
    </Input>
  );
});

const CompoundCombobox = Object.assign(Combobox, {
  Prefix: Input.Prefix,
  Suffix: Input.Suffix,
  List: ComboboxList,
  Item: ComboboxListItem,
});

export { CompoundCombobox as Combobox };
© www.soinside.com 2019 - 2024. All rights reserved.