1. ホーム
  2. reactjs

[解決済み] React Hookでスロットルやデバウンスを使用するには?

2022-12-23 23:36:23

質問

私は throttle メソッドから lodash を機能的なコンポーネントで使用する場合などです。

const App = () => {
  const [value, setValue] = useState(0)
  useEffect(throttle(() => console.log(value), 1000), [value])
  return (
    <button onClick={() => setValue(value + 1)}>{value}</button>
  )
}

の中のメソッドなので useEffect の中のメソッドはレンダリングごとに再宣言されるので、スロットリング効果は働きません。

どなたか簡単な解決策をお持ちではないでしょうか。

どのように解決するのですか?

ある程度時間が経つと、自分で setTimeout/clearTimeout (を使って自分で処理する方が、関数型ヘルパーを使うよりずっと簡単だと思います。後の方の処理は、それを useCallback に適用した直後に、依存関係の変更のために再作成される可能性があるけれども、実行中の遅延をリセットしたくないという追加の課題が発生します。

以下はオリジナルの回答です。

あなたは(そしておそらく必要な)かもしれません useRef を使用して、レンダリングの間に値を保存することができます。ちょうど、それが タイマーのために提案された

というようなもの

const App = () => {
  const [value, setValue] = useState(0)
  const throttled = useRef(throttle((newValue) => console.log(newValue), 1000))

  useEffect(() => throttled.current(value), [value])

  return (
    <button onClick={() => setValue(value + 1)}>{value}</button>
  )
}

については useCallback :

としても使えるかもしれません。

const throttled = useCallback(throttle(newValue => console.log(newValue), 1000), []);

しかし、コールバックを一度作り直そうとすると value が変更されます。

const throttled = useCallback(throttle(() => console.log(value), 1000), [value]);

が実行を遅らせないことがわかるかもしれません。 value が変更されると、コールバックは直ちに再作成され、実行されます。

ということで useCallback は、遅延実行の場合、大きな利点はありません。それはあなた次第です。

[UPD】当初は

  const throttled = useRef(throttle(() => console.log(value), 1000))

  useEffect(throttled.current, [value])

しかし、その方法では throttled.current は初期 value (0)にバインドされています。そのため、次のレンダリングでも変更されることはありませんでした。

ですから、関数を useRef に押し込むときには注意が必要です。