react-selectで全選択の実装
react-selectで独自のボタンと埋め込む時の備忘録
こんなのをしたい
全選択とか全解除で複数選択を楽させたい
成果物
ソース
import React, { useState } from "react";
import "./styles.css";
import ReactSelect, { components, createFilter } from "react-select";
const options = [
{ value: "ocean1", label: "Ocean", color: "#00B8D9" },
{ value: "blue", label: "Blue", color: "#0052CC" },
{ value: "purple", label: "Purple", color: "#5243AA" },
{ value: "red", label: "Red", color: "#FF5630" },
{ value: "orange", label: "Orange", color: "#FF8B00" },
{ value: "yellow", label: "Yellow", color: "#FFC400" },
{ value: "green", label: "Green", color: "#36B37E" },
{ value: "forest", label: "Forest", color: "#00875A" },
{ value: "slate", label: "Slate", color: "#253858" },
{ value: "silver", label: "Silver", color: "#666666" }
];
const widget = {
label: "Hoge",
value: "*"
};
export default function App() {
const [selected, setSelected] = useState([]);
const Option = (props) => {
// 値が*の時は独自のボタンとかを描画
if (props.data.value === "*") {
return (
<div style={{ display: "flex", justifyContent: "space-around" }}>
<button
onClick={() => {
setSelected(options);
}}
>
全選択
</button>
<button
onClick={() => {
setSelected([]);
}}
>
全解除
</button>
</div>
);
}
return <components.Option {...props} />;
};
// 独自UIはfIlterの対象外に
const withOutWidgetFilter = (candidate, input) => {
if (input && candidate.value === "*") {
return true;
}
return createFilter(null)(candidate, input);
};
return (
<div className="App">
<h1>React Select With Widgets Example</h1>
<div style={{ width: "500px", margin: "auto" }}>
<ReactSelect
value={selected}
options={[widget, ...options]}
components={{ Option }}
isMulti
closeMenuOnSelect={false}
hideSelectedOptions={false}
filterOption={withOutWidgetFilter}
onChange={(value) => {
setSelected(value);
}}
/>
</div>
</div>
);
}
解説
肝としては、optionsを拡張して独自の機能を埋め込んでいる
const Option = (props) => {
// 値が*の時は独自のボタンとかを描画
if (props.data.value === "*") {
return (
<div style={{ display: "flex", justifyContent: "space-around" }}>
<button
onClick={() => {
setSelected(options);
}}
>
全選択
</button>
<button
onClick={() => {
setSelected([]);
}}
>
全解除
</button>
</div>
);
}
return <components.Option {...props} />;
};
react-selectの絞り込み機能で埋め込んだUIを絞り込みの対象にしたないときはこうする
const withOutWidgetFilter = (candidate, input) => {
// 独自UI用の値の時はtrueを返しfilteringの対象外に
if (input && candidate.value === "*") {
return true;
}
// デフォルトの絞り込み処理
return createFilter(null)(candidate, input);
};
ざっくりとこんな感じで実現可能です
絞り込んだ値に対しての全選択とかはもう少し処理が必要ですが、ベースはこんな感じです
おまけ
Filterで絞り込まれている値ははSelectのrefから参照できます
const ref = React.useRef(null);
// 絞り込まれた値が取得できる
const filtedOptions = ref.current?.select.state.menuOptions.render || []
return <Select
ref={ref}
{...props}
/>