如何防止 ReactSelect 清除输入?

How to prevent ReactSelect from clearing the input?

我的应用程序中的 ReactSelect 组件在我进行选择后清除我输入的内容。我不希望它那样做。

我希望它保持原样。当用户没有输入任何内容时,我希望它显示占位符文本。

我将此组件用作搜索框。从列表中选择一项即可完成任务。没有理由将组件的值设置为选择。

react-select 不支持开箱即用的自动完成功能,因此需要一些额外的工作和技巧才能获得您想要的内容。

首先,你需要控制inputValue状态,menu-closeset-value等一些操作之后会清除输入。

const [input, setInput] = React.useState("");
const handleInputChange = (e, meta) => {
  if (meta.action === "input-change") {
    setInput(e);
  }
};

return (
  <Select
    value={selected}
    onChange={handleChange}
    inputValue={input}
    isSearchable
    {...}
  />
);

react-select 还会在选择选项后隐藏输入,因此您还需要覆盖该行为。

const [selected, setSelected] = React.useState([]);
const handleChange = (s) => {
  setSelected({ ...s });
};

React.useLayoutEffect(() => {
  const inputEl = document.getElementById("myInput");
  if (!inputEl) return;
  // prevent input from being hidden after selecting
  inputEl.style.opacity = "1";
}, [selected]);

return (
  <Select
    value={selected}
    inputId="myInput"
    onChange={handleChange}
    {...}
  />
);

最后但同样重要的是,您可能希望在成功选择后相应地更新您的输入,这是一个基本示例,下面的代码将在选择后将新的选项值附加到您当前的输入。

同时确保重写默认值 filterOption 以在过滤时仅考虑最后一个词,否则前几个词后的选项将不匹配任何内容。

const [selected, setSelected] = React.useState([]);
const [input, setInput] = React.useState("");
const handleChange = (s) => {
  setSelected({ ...s });
  setInput((input) => removeLastWord(input) + s.value);
};

const customFilter = () => {
  return (config, rawInput) => {
    const filter = createFilter(null);
    return filter(config, getLastWord(rawInput));
  };
};

return (
  <Select
    value={selected}
    filterOption={customFilter()}
    onChange={handleChange}
    inputValue={input}
    components={{
      SingleValue: () => null
    }}
    {...}
  />
);

其中 removeLastWordgetLastWord 只是一些实用函数。

function getLastWord(str: string) {
  return str.split(" ").slice(-1).pop();
}

function removeLastWord(str: string) {
  var lastWhiteSpaceIndex = str.lastIndexOf(" ");
  return str.substring(0, lastWhiteSpaceIndex + 1);
}

这是结合以上所有内容后的完整示例。

import React from "react";
import Select, { components, createFilter } from "react-select";
import options from "./options";

function getLastWord(str: string) {
  return str.split(" ").slice(-1).pop();
}

function removeLastWord(str: string) {
  var lastWhiteSpaceIndex = str.lastIndexOf(" ");
  return str.substring(0, lastWhiteSpaceIndex + 1);
}

export default function MySelect() {
  const [selected, setSelected] = React.useState([]);
  const [input, setInput] = React.useState("");
  const handleChange = (s) => {
    setSelected({ ...s });
    setInput((input) => removeLastWord(input) + s.value);
  };
  const handleInputChange = (e, meta) => {
    if (meta.action === "input-change") {
      setInput(e);
    }
  };

  React.useLayoutEffect(() => {
    const inputEl = document.getElementById("myInput");
    if (!inputEl) return;
    // prevent input from being hidden after selecting
    inputEl.style.opacity = "1";
  }, [selected]);

  const customFilter = () => {
    return (config, rawInput) => {
      const filter = createFilter(null);
      return filter(config, getLastWord(rawInput));
    };
  };

  return (
    <Select
      value={selected}
      filterOption={customFilter()}
      inputId="myInput"
      onChange={handleChange}
      blurInputOnSelect={false}
      inputValue={input}
      onInputChange={handleInputChange}
      options={options}
      isSearchable
      hideSelectedOptions={false}
      components={{
        SingleValue: () => null
      }}
    />
  );
}

实例

您还可以使用 styles 道具覆盖输入样式。在这个 thread

上有关于这个问题的完整讨论
{
  input: (provided) => ({
    ...provided,
    input: {
      opacity: "1 !important",
    },
  }),
}