Downshift:将 inputValue 设置为键盘导航中当前突出显示的项目的值
Downshift: Set inputValue to value of currently highlighted item on keyboard navigation
使用 Downshift,如何实现将 inputValue
设置为 ArrowUp/ArrowDown 上当前突出显示的项目的值,同时保留过滤的项目直到用户手动增加 inputValue
?
例如:
上述行为可以利用 stateReducer
和 useCombobox
挂钩实现,如下所示:
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">
↓
</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"));
使用 Downshift,如何实现将 inputValue
设置为 ArrowUp/ArrowDown 上当前突出显示的项目的值,同时保留过滤的项目直到用户手动增加 inputValue
?
例如:
上述行为可以利用 stateReducer
和 useCombobox
挂钩实现,如下所示:
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">
↓
</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"));