見出し画像

ReactでnoUiSliderを使ったときの覚え書き

最近趣味で作っていたReact(実際にはNext.jsだったんですが)のサイトで、範囲を指定できるスライダーが欲しいタイミングがあったんですね。<input type="range">だとハンドルが1個しかないですし、じゃあライブラリ使うかということで探し、要件を満たしたのがnoUiSliderです。

ですが、ひとつ問題がありました。Reactに対応したnoUiSliderのライブラリが以下のくらいしか見つからなくて、しかもこれは最終更新が2021年だったんですね。

一方で、本家のほうは今年の6月に更新された形跡があります。

ということで、react-nouisliderのほうは使わずに、自分が必要な機能だけ実装したReactのコンポーネントを作成しました。以下がコードの全文です。自分が必要な機能しか実装していないので短いですね。

import { useEffect, useRef } from 'react';
import noUiSlider, { API } from 'nouislider';
import 'nouislider/dist/nouislider.css';

type Props = {
  values: [number, number],
  max: number,
  // eslint-disable-next-line no-unused-vars
  onChange: (values: [number, number]) => void,
}

function Slider(props: Props) {
  const { values, max, onChange } = props;
  const ref = useRef<HTMLDivElement>(null);
  const slider = useRef<API|null>(null);

  useEffect(() => {
    slider.current = noUiSlider.create(ref.current!, {
      start: values,
      step: 1,
      connect: true,
      range: {
        min: 1,
        max,
      },
      format: {
        to(value: number): number {
          return Math.round(value);
        },
        from(value: string): number {
          return Number(value);
        },
      },
      tooltips: true,
    });
    slider.current.on('change', (changedValues) => {
      onChange(changedValues as [number, number]);
    });
    return () => {
      slider.current!.destroy();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    slider.current!.set(values);
  }, [values]);

  return (
    <div ref={ref} />
  );
}

export default Slider;

(改善点はめちゃくちゃ色々あると思いますが許して)

このコンポーネントは親から受け取ったvaluesをスライダーのハンドルに反映して、スライダーのハンドルが操作されたら親にイベントを渡すといった、単方向データフローを実現しています。

余談ですが、こういう入力要素に対する単方向データフローって実際どうやって作ればいいんだって疑問だったんですよね。今回自分でReact用の簡単なコンポーネントを作るにあたって、不完全ながらもやり方がわかって良かったです。

覚え書きと言いつつ本当に簡単なことしかしてないので、他に書くことも特にないですね。もしnoUiSliderをReactで使いたいという人がこの記事に辿り着いたら、ちょっとだけ参考にしてみてください。

この記事が気に入ったらサポートをしてみませんか?