##デモ
App.js
import React, { useState, useEffect, useCallback } from "react";
export default function App() {
const [state, setState] = useState("");
const callback = useCallback(() => {
//この中で更新後の値が使える
console.log("debounced!!!", state);
}, [state]);
useEffect(() => {
const handler = setTimeout(callback, 1000);
//cleanup
return () => {
clearTimeout(handler);
};
},[callback);
return (
<div className="App">
<input type="text" value={state} onChange={e => setState(e.target.value)} />
</div>
);
}
普通にlodashとか使って作ったdebounce関数をuseEffectにぶちこむと更新後のstateを使うためには引数として渡さなければいけないのですが、useEffectのcleanup関数をうまく使ってあげることでstateが変わりcallback関数が再作成されるたびcleanupの中のclearTimeoutが待機中だった処理をキャンセルして、effectの中で新しいsetTimeoutを作成することでdebounce処理を行うことができます。
##customHook版
useDebouncedEffect.js
import { useEffect, useCallback } from "react";
const useDebounceeEffect = (effect, deps, delay) => {
const callback = useCallback(effect, deps);
useEffect(() => {
const handler = setTimeout(callback, delay);
//cleanup
return () => {
clearTimeout(handler);
};
}, [callback, delay]);
};
export default useDebounceeEffect;
App.js
import React, { useState } from "react";
import useDebouncedEffect from "./useDebouncedEffect";
export default function App() {
const [text, setText] = useState("");
useDebouncedEffect(
() => {
console.log("debounced!!!", text);
},
[text],
1000
);
return (
<div className="App">
<input type="text" value={text} onChange={e => setText(e.target.value)} />
</div>
);
}
これでかんたんにstateの更新と紐付けたdebounce処理ができます
やったぜ。