LoginSignup
2
1

More than 3 years have passed since last update.

react-selectで全選択とか独自UIの実装 & filterOptionのコントロール

Posted at

react-selectで全選択の実装

react-selectで独自のボタンと埋め込む時の備忘録

こんなのをしたい

全選択とか全解除で複数選択を楽させたい

スクリーンショット 2020-10-12 18.38.19.png

成果物

codesandbox

ソース

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}
       />
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1