Skip to content

useTypeahead

提供匹配的回调,可用于在用户键入时聚焦项目,与 useListNavigation() 一起使用。

¥Provides a matching callback that can be used to focus an item as the user types, used in tandem with useListNavigation().

import {useTypeahead} from '@floating-ui/react';

这对于创建具有预先输入支持的菜单非常有用,用户可以在其中键入以聚焦某个项目,然后立即选择它,特别是当它包含大量项目时。

¥This is useful for creating a menu with typeahead support, where the user can type to focus an item and then immediately select it, especially if it contains a large number of items.

有关创建可组合子 API 组件的信息,请参阅 FloatingList

¥See FloatingList for creating composable children API components.

用法

¥Usage

该 Hook 返回事件处理程序 props。

¥This Hook returns event handler props.

要使用它,请将 useFloating() 返回的 context 对象传递给它,然后将其结果输入 useInteractions() 数组。然后将返回的 prop getter 传播到元素上进行渲染。

¥To use it, pass it the context object returned from useFloating(), and then feed its result into the useInteractions() array. The returned prop getters are then spread onto the elements for rendering.

useListNavigation() 负责同步焦点索引。

¥useListNavigation() is responsible for synchronizing the index for focus.

function App() {
  const [activeIndex, setActiveIndex] = useState(null);
 
  const {refs, floatingStyles, context} = useFloating({
    open: true,
  });
 
  const items = ['one', 'two', 'three'];
 
  const listRef = useRef(items);
 
  const typeahead = useTypeahead(context, {
    listRef,
    activeIndex,
    onMatch: setActiveIndex,
  });
 
  const {getReferenceProps, getFloatingProps, getItemProps} =
    useInteractions([typeahead]);
 
  return (
    <>
      <div ref={refs.setReference} {...getReferenceProps()}>
        Reference element
      </div>
      <div
        ref={refs.setFloating}
        style={floatingStyles}
        {...getFloatingProps()}
      >
        {items.map((item, index) => (
          <div
            key={item}
            // Make these elements focusable using a roving tabIndex.
            tabIndex={activeIndex === index ? 0 : -1}
            {...getItemProps()}
          >
            {item}
          </div>
        ))}
      </div>
    </>
  );
}

属性

¥Props

interface UseTypeaheadProps {
  listRef: React.MutableRefObject<Array<string | null>>;
  activeIndex: number | null;
  onMatch?(index: number): void;
  enabled?: boolean;
  resetMs?: number;
  ignoreKeys?: Array<string>;
  selectedIndex?: number | null;
  onTypingChange?(isTyping: boolean): void;
  findMatch?:
    | null
    | ((
        list: Array<string | null>,
        typedString: string,
      ) => string | null | undefined);
}

listRef

Required

默认:空列表

¥default: empty list

包含索引与列表的 HTML 元素匹配的字符串数组的 ref。

¥A ref which contains an array of strings whose indices match the HTML elements of the list.

const listRef = useRef(['one', 'two', 'three']);
 
useTypeahead(context, {
  listRef,
});

如果字符串预先不可用,你可以在分配节点时派生这些字符串:

¥You can derive these strings when assigning the node if the strings are not available up front:

// Array<HTMLElement | null> for `useListNavigation`
const listItemsRef = useRef([]);
// Array<string | null> for `useTypeahead`
const listContentRef = useRef([]);
<li
  ref={(node) => {
    listItemsRef.current[index] = node;
    listContentRef.current[index] = node?.textContent ?? null;
  }}
/>

禁用的项目可以由数组中相关索引处的 null 值表示,并且将被跳过。

¥Disabled items can be represented by null values in the array at the relevant index, and will be skipped.

activeIndex

Required

默认:null

¥default: null

当前活跃的索引。这指定了预输入的开始位置。

¥The currently active index. This specifies where the typeahead starts.

const [activeIndex, setActiveIndex] = useState(null);
 
useTypeahead(context, {
  activeIndex,
});

onMatch

默认:no-op

¥default: no-op

如果在用户键入时找到匹配的索引,则会调用回调。

¥Callback invoked with the matching index if found as the user types.

const [isOpen, setIsOpen] = useState(false);
const [activeIndex, setActiveIndex] = useState(null);
const [selectedIndex, setSelectedIndex] = useState(null);
 
useTypeahead(context, {
  onMatch: isOpen ? setActiveIndex : setSelectedIndex,
});

enabled

默认:true

¥default: true

有条件地启用/禁用 Hook。

¥Conditionally enable/disable the Hook.

useTypeahead(context, {
  enabled: false,
});

findMatch

默认:小写查找器

¥default: lowercase finder

如果你想实现自定义查找逻辑(例如 模糊搜索),你可以使用此回调。

¥If you’d like to implement custom finding logic (for example fuzzy search), you can use this callback.

useTypeahead(context, {
  findMatch: (list, typedString) =>
    list.find(
      (itemString) =>
        itemString?.toLowerCase().indexOf(typedString) === 0,
    ),
});

resetMs

默认:750

¥default: 750

反跳超时将在用户键入时重置瞬态字符串。

¥Debounce timeout which will reset the transient string as the user types.

useTypeahead(context, {
  resetMs: 500,
});

ignoreKeys

默认:[]

¥default: []

要忽略的可选键。

¥Optional keys to ignore.

useTypeahead(context, {
  ignoreKeys: ['I', 'G', 'N', 'O', 'R', 'E'],
});

selectedIndex

默认:null

¥default: null

当前选择的索引(如果可用)。

¥The currently selected index, if available.

const [selectedIndex, setSelectedIndex] = useState(null);
 
useTypeahead(context, {
  selectedIndex,
});

onTypingChange

默认:no-op

¥default: no-op

当用户键入时,使用键入状态调用回调。

¥Callback invoked with the typing state as the user types.

useTypeahead(context, {
  onTypingChange(isTyping) {
    // ...
  },
});