66
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

NIJIBOXAdvent Calendar 2022

Day 21

react-useで使える便利なReact Hooksを紹介します

Last updated at Posted at 2022-12-21

react-use とは

様々な React の Hooks を定義しているライブラリです。
用意されている Hooks の数が多く、バリエーションも豊富な為、これから作ろうと思っていた Hooks が react-use に既にあった、という事が起こり得ます。
Hooks の数が膨大なので、簡単な一つの Hooks を使う為だけにこのライブラリを導入するべきかは要検討ですが、ある程度の規模のプロダクトであれば色々なところで利用する局面はありそうです。

インストール

## yarnの場合
yarn add react-use

## npmの場合
npm i react-use

用意されている Hooks 一覧

数が多いのと、日々更新されているので、全項目は網羅出来ておりません。
全ての Hooks を確認したい場合は、公式の GitHub をご参照ください。

状態感知系

Hooks 説明
useBattery デバイスのバッテリー状況を取得する
useGeolocation ユーザーの位置情報を取得する
useHover と useHoverDirty 要素がマウスでホバーされているかどうかを追跡する
useHash URLハッシュの取得や、ハッシュの設定が行える
useIdle ページ上のユーザーがアイドル状態であるかどうかを追跡する
useIntersection ターゲット要素と祖先要素、または最上位ドキュメントのビューポートとの交差の変化を追跡する
useKey キーボードのキーが使用されたときにコールバックを実行する
useLocation ブラウザロケーションを取得する
useLongPress クリックを長押しした際にコールバックを発生させる
useMedia メディアクエリで状態を切り替える
useMediaDevices 接続されたハードウェアデバイスを追跡する
useMotion デバイスの加速度センサーを使用してモーションを追跡する
useMouse と useMouseHovered マウスの位置が変化したときに再レンダリングする
useMouseWheel ウィンドウでスクロールされたマウスの deltaY を取得する
useNetworkState ブラウザのネットワーク接続の状態を追跡する
useOrientation ユーザーのデバイスの画面の向きを追跡する
usePageLeave マウスがページから離れたときにコールバックを発生させる
useScratch マウスの「スクラブ」(または「スクラッチ」) の状態を追跡する
useScroll DOM 要素のスクロール位置が変更されたときに再レンダリングする
useScrolling ユーザーがスクロールしているかどうかを追跡する
useStartTyping ユーザーが入力を開始したときにコールバックを発生させる
useWindowScroll ウィンドウのスクロール時に再レンダリングする
useWindowSize ブラウザウィンドウのサイズを追跡する
useMeasure Resize Observer APIを使用して HTML 要素の寸法を追跡する
createBreakpoint ブレークポイントを設定する
useScrollbarWidth 現在のブラウザのスクロールバーの幅を返す
usePinchZoom ポインター、タッチイベントの変化を追跡し、ピンチ差の値を検出して、ユーザーがズームインまたはズームアウトしているかどうかを通知する

UI系

Hooks 説明
useAudio audio 要素を作成し、再生コントロールを表示する
useClickAway ユーザーがターゲット要素の外側をクリックしたときにコールバックする
useCss CSS を動的に変更する
useDrop と useDropArea ファイル、リンクのドロップ、およびコピーと貼り付けでトリガーされる
useFullscreen 要素をフルスクリーンで表示する
useSlider HTML 要素上でスライド動作を提供する
useSpeech 与えられた文字列を話す人間の声を合成する
useVibrate Vibration APIを使用してデバイスのバイブレーションを発生させる
useVideo video 要素を作成し、再生コントロールを表示する

アニメーション系

Hooks 説明
useRaf requestAnimationFrameごとにコンポーネントを強制的に再レンダリングし、経過時間のパーセンテージを返す
useInterval 数値のカウントアップなど、間隔をセットして、状態の変化をアニメーションさせる
useHarmonicIntervalFn useIntervalと似ているが、こちらはすべてのエフェクトを同じ遅延で同時にトリガーする
useSpring スプリングの動きに合わせて一つの数値を時間と共に更新する
useTimeout 指定されたミリ秒後にコンポーネントを再レンダリングする
useTimeoutFn 指定されたミリ秒後に指定された関数を呼び出す
useTween 0 と 1 の間の数値をトゥイーンする
useUpdate 呼び出されたときにコンポーネントを強制的に再レン​​ダリングする関数を返す

副作用系

Hooks 説明
useAsync 非同期関数をコンポーネント内で同期的に扱うことを可能にする
useBeforeUnload ユーザーがページを再読み込みまたは閉じようとしたときにブラウザのアラートを表示する
useCookie Cookie の現在の値を返したり、更新、削除を行う
useCopyToClipboard テキストをユーザーのクリップボードにコピーする
useDebounce 連続する処理が指定した時間内に何度発生しても、最後の一度だけ実行する
useError エラーディスパッチャーを返す
useFavicon ページのファビコンを設定する
useLocalStorage LocalStorageにて、単一のキーでデータを管理する
useLockBodyScroll body 要素のスクロールをロックする
useRafLoop 親コンポーネントを再描画することなく、RAFのループ内で指定された関数を呼び出す。ループはコンポーネントのアンマウント時に自動的に停止する
useSessionStorage SessionStorageにて、単一のキーでデータを管理する
useThrottle と useThrottleFn 指定したミリ秒が経過するまで、関数の呼び出しを遅延させる
useTitle ページのタイトルを設定する
usePermission ブラウザAPIのパーミッション状況を問い合わせる

ライフサイクル系

Hooks 説明
useEffectOnce 一度だけ実行される useEffect
useEvent イベントハンドラをサブスクライブする
useLifecycles コンポーネントがマウントされたときとアンマウントされたときに、mount と unmount のコールバックを呼び出す
useMountedState コンポーネントがマウントされているかどうかを返す
usePromise Promise をラップするためのヘルパー関数を返す。この関数でラップされた Promise は、コンポーネントがマウントされたときのみ解決される
useLogger コンポーネントがライフサイクルを通じて遷移する際に、パラメータをコンソールログに記録する
useMount コンポーネントがマウントされた後に関数を呼び出す
useUnmount コンポーネントがアンマウントされるときに関数を呼び出す
useUpdateEffect 最初の呼び出し (マウント時など) を無視する

state系

Hooks 説明
createMemo 指定した関数をメモ化する。元の関数と同じ引数を受け取り、同じ結果を返す
createReducerContext React の useReducer と同じ振る舞いをするが、 Context として全てのコンポーネントで共有される
useDefault 状態が null または未定義の場合にデフォルト値を返す
useLatest State の最新の状態を返す
usePrevious State の前の値を返す
usePreviousDistinct usePrevious と同じだが、値が実際に変更された場合にのみ更新される
useSetState クラスコンポーネントの this.setState の動作と同様に動作する setState メソッドを作成する
useToggle 状態の Boolean を反転させる
useCounter 数値カウントを追跡する
useList 配列の値を追跡し、それを変更するためのメソッドを提供する
useMap オブジェクトの値を追跡し、それを変更するためのメソッドを提供する
useStateValidator 指定された State が変化するたびに、バリデータ関数が呼び出される
useRendersCount 最初のレンダリングを含む、コンポーネントのレンダリング回数をトラッキングする
useGlobalState グローバルに共有される State を作成する

使用例紹介

数が多いので全ては紹介できませんが、個人的に面白いと思った Hooks をピックアップします。

useHover

要素が Hover されているかどうかを追跡します。
引数に指定した React 要素が Hovered のターゲットとなり、Hover されていればコンポーネントを表示する、というような処理が出来ます。

import { useHover } from "react-use";

export default function App() {
  const hoverTargetElement = (hovered) => <div>{hovered ? "Hovered" : "Hover me!"}</div>;
  const [hoverable, hovered] = useHover(hoverTargetElement);

  return (
    <div>
      {hoverable}
      {hovered && <div>Hoverされました</div>}
    </div>
  );
}

useKey

キーボードの入力を受け取って、指定した処理を実行します。
第一引数にKeyboardEvent.keyプロパティの値、第2引数にイベントハンドラを渡します。
例えば、上矢印入力でカウントアップ、下矢印入力でカウントダウンを行う場合は以下のようになります。

import { useKey } from "react-use";

export default function App() {
  const [count, set] = useState(0);
  const increment = () => set((count) => ++count);
  const decrement = () => set((count) => --count);
  useKey("ArrowUp", increment);
  useKey("ArrowDown", decrement);

  return <div>Press arrow up: {count}</div>;
}

useMedia

メディアクエリで状態の出し分けを行えます。
PC レイアウトと SP レイアウトを、指定したブレークポイントを起点に切り替える事が出来ます。

import { useMedia } from 'react-use'

export default function App() {
  const isWide = useMedia('(min-width: 480px)')
  return (
    <>
      <div>{isWide ? (<div>PC Contents</div>) : (<div>SP contents</div>)}</div>
    </>
  )
}

useToggle

状態の Boolean を反転させる Hooks です。
Toggle 系の処理は簡単なのですぐに実装出来ますが、利用箇所が多くなればなる程この Hooks の便利さに気付けます。

import { useToggle } from 'react-use'

export default function App() {
  const [on, toggle] = useToggle(false)
  return (
    <>
      <button onClick={toggle}>{on ? 'active' : 'inactive'}</button>
    </>
  )
}

useClickAway

ターゲット要素の範囲外がクリックされた際にコールバックする Hooks です。
例えば、モーダルの実装で範囲外がクリックされた場合にモーダルを閉じる、というような挙動を実装するのに便利です。
以下は、Button クリックで要素の出し分けを行い、要素の外側がクリックされた場合にも非表示処理を行なっています。

import { useClickAway, useToggle } from 'react-use'

export default function App() {
  const [on, toggle] = useToggle(false)
  const ref = useRef(null)
  useClickAway(ref, () => {
    toggle()
  })
  return (
    <>
      {on && (
        <div
          ref={ref}
          style={{
            width: 200,
            height: 200,
            background: 'red',
          }}
        />
      )}
      <button onClick={toggle}>{on ? 'close' : 'open'}</button>
    </>
  )
}

usePageLeave

マウスが画面外に飛び出した際に発火する Hooks です。
面白かったので、どんな時に使えるのかを考えてみたのですが、何も浮かびませんでした・・・。

import { usePageLeave } from 'react-use'

export default function App() {
    usePageLeave(() => alert('Stay here'))

    return null;
}

useSessionStorage

セッションストレージにデータを保存します。
第一引数にストレージのキー、第二引数に初期値、第三引数は JSON 形式にシリアライズするかどうかを Boolean で渡します。
JSON.stringify でシリアライズ化して、 JSON.parse でデシリアライズ化するという一連の流れを全部やってくれます。
ちなみにuseLocalStorage も用意されていて、そちらではシリアライズをカスタマイズできるみたいです。

import { useSessionStorage } from 'react-use'

export default function App() {
  const [sessionStorage, setSessionStorage] = useSessionStorage('my-key', 'foo')
  const [value, setValue] = useState('')

  const handleSubmit = () => {
    setSessionStorage(value)
  }

  const handleChange = (e) => {
    setValue(e.target.value)
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" value={value} onChange={handleChange} />
      </label>
      <button type="submit">Submit</button>
      <div>storage: {sessionStorage}</div>
    </form>
  )
}

useCookie

Cookie の値を読んだり、更新したり、削除したり。

import { useCookie } from 'react-use'

export default function App() {
  const [cookieValue, updateCookie, deleteCookie] = useCookie('cookie')

  useEffect(() => {
    deleteCookie()
  }, [])

  const updateCookieHandler = () => {
    updateCookie(Math.random().toString(32).substring(2))
  }

  return (
    <div>
      <p>cookie value: {cookieValue}</p>
      <button onClick={updateCookieHandler}>Update Cookie</button>
      <br />
      <button onClick={deleteCookie}>Delete Cookie</button>
    </div>
  )
}

useLockBodyScroll

body のスクロールをロックする Hooks です。
モーダルやオーバーレイコンポーネントに使えます。

import { useLockBodyScroll, useToggle } from 'react-use'

export default function App() {
  const [locked, toggleLocked] = useToggle(false)

  useLockBodyScroll(locked)

  return (
    <div style={{
          display: 'flex'
        }}>
      <div
        style={{
          width: 200,
          height: '150vh',
          background: 'red',
        }}
      />
      <button onClick={() => toggleLocked()}>{locked ? 'Unlock' : 'Lock'}</button>
    </div>
  )
}

useDefault

状態が null または undefined の場合に使用する、デフォルト値を保持する事ができます。
第一引数にデフォルト値、第二引数に初期値とし、状態が null または undefined になった場合にデフォルト値が呼ばれます。

import { useDefault } from 'react-use'

export default function App() {
  const initialUser = { name: 'initial' }
  const defaultUser = { name: 'default' }
  const [user, setUser] = useDefault(defaultUser, initialUser)

  return (
    <div>
      <div>User: {user.name}</div>
      <input onChange={(e) => setUser({ name: e.target.value })} />
      <button onClick={() => setUser(null)}>set to null</button>
    </div>
  )
}

useScrolling

指定した Ref オブジェクトがスクロール状態であるかどうかを追跡します。
スクロール中かそうでないかで処理を出し分ける事が可能です。

import { useScrolling } from 'react-use'

export default function App() {
  const scrollRef = useRef(null)
  const scrolling = useScrolling(scrollRef)

  return (
    <div
      ref={scrollRef}
      style={{
        display: 'flex',
        height: '100vh',
        overflow: 'scroll',
      }}
    >
      <div
        style={{
          width: 200,
          height: '150vh',
          background: 'red',
        }}
      />
      <div
        style={{
          position: 'fixed',
        }}
      >
        {<div>{scrolling ? 'Scrolling' : 'Not scrolling'}</div>}
      </div>
    </div>
  )
}

usePrevious

State の前の状態を保持してくれる Hooks です。
前回の値と比較を行う際など、わざわざ値を記録しておく必要がなくなるので、とても便利です。

import { usePrevious } from 'react-use'

export default function App() {
  const [value, setValue] = useState('')
  const prev = usePrevious(value)

  return (
    <div>
      <p>value: {value}</p>
      <p>prev: {prev}</p>
      <input onChange={(e) => setValue(e.target.value)} />
    </div>
  )
}

useCopyToClipboard

テキストをユーザーのクリップボードにコピーします。
copyToClipboardにコピーしたいテキストを渡すだけです。stateに状態を保持しており、コピー出来なかった場合はエラーを入れてくれたり、コピーが出来た場合は value を呼び出せたりします。

import { useCopyToClipboard } from 'react-use'

export default function App() {
  const [text, setText] = useState('')
  const [state, copyToClipboard] = useCopyToClipboard()

  return (
    <div>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <button type="button" onClick={() => copyToClipboard(text)}>
        copy text
      </button>
      {state.error ? (
        <p>Unable to copy value: {state.error.message}</p>
      ) : (
        state.value && <p>Copied {state.value}</p>
      )}
    </div>
  )
}

useUpdateEffect

初回レンダー時に実行が無視される useEffect です。
指定した状態だけに依存して実行したい処理を useEffect で記述しても、初回レンダー時は実行されてしまいます。
それを防いでくれるのがこの Hooks です。

import { useUpdateEffect } from 'react-use'

export default function App() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    const interval = setInterval(() => {
      setCount((c) => c + 1)
    }, 10000)

    return () => {
      clearInterval(interval)
    }
  }, [])

  useUpdateEffect(() => {
    console.log('count', count)
  }, [count])

  return <div>Count: {count}</div>
}

まとめ

react-use で使用できる 便利な Hooks を紹介いたしました。
React Hooks に関しては、react-use だけでなく様々なライブラリが出回っているので、これから実装しようと思っている Hooks が車輪の再発明になっていないか調べてみると良いかもしれません。

また、react-use で使用できる殆どの Hooks が こちら でデモを確認できます。これを触っているだけでも楽しいと思います。
GitHub から実装されている Hooks の中身も確認できるので、こちらも確認してみると多くの学びがあるかと思います。

66
47
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
66
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?