Downshift:将 inputValue 设置为键盘导航中当前突出显示的项目的值

Downshift: Set inputValue to value of currently highlighted item on keyboard navigation

使用 Downshift,如何实现将 inputValue 设置为 ArrowUp/ArrowDown 上当前突出显示的项目的值,同时保留过滤的项目直到用户手动增加 inputValue

例如:

上述行为可以利用 stateReduceruseCombobox 挂钩实现,如下所示:

import React, { useState } from "react";
import { render } from "react-dom";
import { useCombobox } from "downshift";
import { items, menuStyles } from "./utils";

function stateReducer(state, actionAndChanges) {
  switch (actionAndChanges.type) {
    case useCombobox.stateChangeTypes.InputChange:
      return {
        ...actionAndChanges.changes,
        userInput: actionAndChanges.changes.inputValue
      };
    case useCombobox.stateChangeTypes.InputKeyDownArrowDown:
    case useCombobox.stateChangeTypes.InputKeyDownArrowUp:
      if (!actionAndChanges.changes.inputValue) return actionAndChanges.changes;

      return {
        ...actionAndChanges.changes,
        userInput: actionAndChanges.changes.inputValue,
        inputValue: actionAndChanges.getItemNodeFromIndex(
          actionAndChanges.changes.highlightedIndex
        ).innerText
      };
    default:
      return actionAndChanges.changes; // otherwise business as usual.
  }
}

function DropdownSelect() {
  const [inputItems, setInputItems] = useState(items);
  const {
    isOpen,
    getToggleButtonProps,
    getLabelProps,
    getMenuProps,
    getInputProps,
    getComboboxProps,
    highlightedIndex,
    getItemProps
  } = useCombobox({
    items: inputItems,
    stateReducer,
    onInputValueChange: ({ userInput, inputValue }) => {
      if (userInput === inputValue) {
        const filteredItems = items.filter(item =>
          item.toLowerCase().startsWith(inputValue.toLowerCase())
        );
        setInputItems(filteredItems);
      }
    }
  });

  return (
    <React.Fragment>
      <label {...getLabelProps()}>Choose an element:</label>
      <div style={{ display: "inline-block" }} {...getComboboxProps()}>
        <input {...getInputProps()} />
        <button {...getToggleButtonProps()} aria-label="toggle menu">
          &#8595;
        </button>
      </div>
      <ul {...getMenuProps()} style={menuStyles}>
        {isOpen &&
          inputItems.map((item, index) => (
            <li
              style={
                highlightedIndex === index ? { backgroundColor: "#bde4ff" } : {}
              }
              key={`${item}${index}`}
              {...getItemProps({ item, index })}
            >
              {item}
            </li>
          ))}
      </ul>
    </React.Fragment>
  );
}

render(<DropdownSelect />, document.getElementById("root"));

View the Code sandbox here