未経験からエンジニア 奮闘記

未経験からエンジニアに自由に生きる途中

MENU

React debounce 実装

debounce とは?

debounceは頻繁に実行する関数

関連技術

  • setTimeout

どんな時に使うの?

このように検索フォームと、データの一覧があるとします

コードはこんな感じで、実装概要は下記 1. axiosでAPIからデータを取得(ここでは jsonplaceholderを利用) 2.検索フォームがある状態 3.useEffectで keywordを監視してるので、キーワードが入力する度にAPIにリクエストを実行する

import { useEffect, useState } from "react"
import axios from "axios"

const SampleForm = () => {
  const [posts, setPosts] = useState([])
  const [keyword, setkeyword] = useState('')
  const handleChaneg = (e) => {
    setkeyword(e.target.value)
  }

  useEffect(() => {
    const fetchPosts = async () => {
      const params = {
        keyword,
    }
    const urlSearchParam =  new URLSearchParams(params).toString();
      const response = await axios.get(`https://jsonplaceholder.typicode.com/posts?${urlSearchParam}`)
      const data = await response.data;
      setPosts(data)      
    }

    fetchPosts()

  },[keyword])  

  if (posts && posts.length == 0) {
    return <> loading...</>
  }

  console.log('レンダリング')

  return (<>
    <input type="text" onChange={handleChaneg}/>

    
    {posts.map((post) => (<><li>{post.title}</li></>))}
  </>)
}

export default SampleForm

何が問題なの?

先ほどのコードに console.logを仕込んでいました。 キーワードを入力する度に、APIfetchPosts 関数が実行されるので、console.logの出力から何回も レンダリングが表示されているのがわかります 1文字1文字入力する度にAPIにリクエストしても、検索の単語として意味を成していないので不要なAPIリクエストになります

また、Google Cloud でCloud RunをAPIで利用していた場合、インフラの金額は、ざっくりいくとリクエスト回数で金額が変わってくるので不要なリクエストでインフラコストが上がってしまいます

ではどおすれば良いのか?

ここで、debounce のテクニックが登場します lodash のライブラリが debounce の関数を提供しています

debounceは何をするものなのか?

・指定した関数の遅延実行を行う ・指定した関数の遅延中に再度同じ関数が実行された場合、直前に実行していた関数はリセットされる

修正したコートは下記になります。

debounceの引数に、fetchPosts 関数を入れる、遅延させる時間を指定するだけで実装できます

'use client'
import { useEffect, useState } from "react"
import axios from "axios"
import { debounce } from 'lodash'

const SampleForm = () => {
  const [posts, setPosts] = useState([])
  const [keyword, setKeyword] = useState('')

  // デバウンスされた関数を作成
  const fetchPosts = debounce(async (keyword) => {
    const params = { keyword }
    const urlSearchParam = new URLSearchParams(params).toString()
    const response = await axios.get(`https://jsonplaceholder.typicode.com/posts?${urlSearchParam}`)
    setPosts(response.data)
  }, 1500) // 1500ミリ秒デバウンス

  useEffect(() => {
    if (keyword) {
      fetchPosts(keyword)
    }
  }, [keyword])

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

  if (posts.length === 0) {
    return <>Loading...</>
  }

  console.log('レンダリング')

  return (
    <>
      <input type="text" onChange={handleChange} />
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </>
  )
}

export default SampleForm

これで、不要なAPIリクエストを減らすことが可能になります

まとめ

debounceのテクニックはAPIに不要なリクエストを実行しないようにするテクニックです。 どんな時に使うのか?は今回の例の様にインクリメンタルサーチなどで利用されることが多い様に思います。 もし、不要にAPIリクエストを実施しているなと思った場合は今回の実装を参考にしてみてください