3
0

【React】検索ボックス実装時のパフォーマンス改善案①

Last updated at Posted at 2024-01-16

検索ボックスを実装したら画面が重たくなった…
という経験はないでしょうか。

考えられる原因はいくつかあると思いますが、基本的にonChangeが悪さをしていることが多いです。

原因:テキストが入力されるたびにonChangeで重たい処理が実行されてしまっている

処理が重くなりがちな例

example.js
const filteringName = (inputValue) => {
    // 高負荷な処理
    someHeavyProcessing();
    
    if (inputValue) {
      const filteredNames = nameListData.filter((name) =>
        name.toLowerCase().includes(inputValue.toLowerCase())
      );
      setNameList(filteredNames);
    } else {
      setNameList(nameListData);
    }
};

...

<TextField
  margin="normal"
  fullWidth
  onChange={(e) => filteringName(e.currentTarget.value)}
/>

文字が入力されたり消されたりするたびに直接処理を呼び出しているため、処理の重さやユーザーのタイピング速度によってパフォーマンスに影響がでやすい。

解決策

テキスト入力が終わってから処理が実行されるようにカスタムフックを作ります。

useDebounce.js
import { useState, useEffect } from "react";

export function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(timer);
    };
  }, [value, delay]);

  return debouncedValue;
}

このカスタムフックでは第一引数に更新するstate,第二引数に何秒間の猶予を持たせるかを設定して発火のタイミングを調整します。

例のコードに当てはめてみる

example.js
import { useDebounce } from "../customHooks/useDebounce";

...

  const [nameList, setNameList] = useState(nameListData);
  // ↓onChange用
  const [inputText, setInputText] = useState("");
  // ↓今回はonChangeで更新されたテキストを0.5秒後にdebouncedInputTextとして返す設定にする
  const debouncedInputText = useDebounce(inputText, 500);

  const filteringName = (inputValue) => {
    // 高負荷な処理
    someHeavyProcessing();
    
    if (inputValue) {
      const filteredNames = nameListData.filter((name) =>
        name.toLowerCase().includes(inputValue.toLowerCase())
      );
      setNameList(filteredNames);
    } else {
      setNameList(nameListData);
    }
  };

 // ↓useEffectを使ってdebouncedInputTextの値が更新されたタイミングで処理を走らせる
  useEffect(() => {
    filteringName(debouncedInputText);
  }, [debouncedInputText]);

...

<TextField
  margin="normal"
  fullWidth
  onChange={(e) => setInputText(e.currentTarget.value)}
/>

流れを整理すると
① テキストフィールドにテキストが入力される
② 0.5秒間テキストが入力されなくなったらuseDebounceが値を返す
③ useDebounceの値更新をuseEffectで検知して本命の処理を実行させる

実際の動き
useDebounce.gif

このようにすることで高負荷な処理があったとしても、文字が入力されるたびに実行されるのを防ぐことができます。

参考にさせていただいた記事

関連記事

3
0
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
3
0