🦥

useDeferredValueが待てない貴方に贈るuse-lazy-state

2022/03/07に公開

追記:React18がリリースされました。 https://reactjs.org/blog/2022/03/29/react-v18.html#react-dom-client

結構前に社内用に書いて使っている便利hooksの供養。

useDeferredValueが何なのかは皆さんご存知だとおもうので省略します。

use-debouncehttps://zenn.dev/hatchinee/articles/3e2ee63ea48b0a で書いたものです。

import {useState} from 'react';

import {useDebounce} from './use-debounce';

/**
 * useDeferredValueが使えるようになるまでのつなぎ。
 * https://reactjs.org/docs/concurrent-mode-reference.html#usedeferredvalue
 */
export function useLazyState<T>(defaultValue: T): [state: T, lazyState: T, setState: (v: T) => void] {
  const [state, setState] = useState(defaultValue);
  const [lazyState, setLazyState] = useState(defaultValue);
  const debouncedSetState = useDebounce(
    (v: T) => {
      setLazyState(v);
    },
    500,
    [defaultValue],
  );

  const setStateHandler = (v: T) => {
    setState(v);
    debouncedSetState(v);
  };

  return [state, lazyState, setStateHandler];
}

はい。
こういう風に使えます。

import {useLazyState} from '~/helpers/use-lazy-state';

// ...

  const [searchWords, lazySearchWords, setSearchWord] = useLazyState('');
  console.log(searchWords, lazySearchWords);

たとえばインクリメンタルサーチをするinputとか、そういうところで使うと便利です。
あとマークダウンのリアルタイムプレビューとか。

debounceとかthrottleでイベントを間引けばよくない? という気持ちはなくもないですが、こっちのほうがコードが直感的で綺麗ですよね。

次のメジャーバージョンでuseDeferredValueがきたら、そっちを使うように書き換えましょう。

以上。

Discussion