🦥
useDeferredValueが待てない貴方に贈るuse-lazy-state
追記:React18がリリースされました。 https://reactjs.org/blog/2022/03/29/react-v18.html#react-dom-client
結構前に社内用に書いて使っている便利hooksの供養。
useDeferredValueが何なのかは皆さんご存知だとおもうので省略します。
use-debounce
は https://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