[React] ユーザーの入力を待ってからFunctionを実行する

June 18, 2021

programming
article cover
Image by ConvertKit

Problem

ユーザーがフォームに入力すると同時に検索結果を表示するリアルタイム検索を実装する場合、onChangeイベントで入力のたびにfunctionを実行すれば問題ないが、APIなどを叩いている場合必要以上に叩いてしまうことになる。

api is called everytime you put a character in input form

Solution

これを防ぐにはユーザーがある程度入力し終わったであろうよきタイミングでFunctionを実行してやる必要があるが、 setTimeoutをうまく活用することでこれを実現することができる。

setTimeout(function, milliseconds, param1, param2, …)

The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds.

仕組みとしては、ユーザーが文字を入力するたびに〇〇秒後に(仮に0.5秒とする)Functionを実行するというタイマーを設定し、 次の文字が入力された際は先に設定しておいたタイマーを取り消してから新たなタイマーを設定する。 こうすることでユーザーの連続した入力が終了した0.5秒後にはじめてFunctionが実行される。

visual explanation

Code

1. useEffectを使う場合

import React, { useState, useEffect } from 'react'

const fakeApi = () => console.log('Api is called')

export default function App() {
  const [inputValue, setInputValue] = useState('')

  useEffect(() => {
    const timer = setTimeout(() => {
      fakeApi()
    }, 500)

    return () => clearTimeout(timer)
  }, [inputValue])

  return (
    <div>
      <label>Input: </label>
      <input
        value={inputValue}
        type="text"
        onChange={e => setInputValue(e.target.value)}
      />
    </div>
  )
}

useEffectは第二引数で指定した変数が更新されるたびに実行されるため、それを利用してinput valueが変わるたびにタイマーを設定し直している。

2. useEffect無し

import React, { useState, useEffect } from 'react'

const fakeApi = () => console.log('Api is called')

export default function App() {
  const [inputValue, setInputValue] = useState('')
  const [timer, setTimer] = useState(null)

  const inputChanged = e => {
    setInputValue(e.target.value)

    clearTimeout(timer)

    const newTimer = setTimeout(() => {
      fakeApi()
    }, 500)

    setTimer(newTimer)
  }
  
  return (
    <div>
      <label>Input: </label>
      <input value={inputValue} type="text" onChange={inputChanged} />
    </div>
  )
}
a function is executed only after user stops typing

Profile picture

元カメラマン。今はベルリンで働くWEBエンジニア。
スロバキア人の妻とドイツ猫二匹の多国籍家族。