I've been implementing a search as you type feature and would like to have the function search which handles my API calls to be debounced. Which works fine if I only call the debounced_search function within the event handler, but I also need to update the input value, which should happen immediately.
My issue is now that as soon as I add setInput(newInputValue); to the event handler, the search function is no longer debounced but gets called immediately on every change though I'm using the debounced version.
Why does that happen? And how do I solve this?
Thank you.
import React from 'react'
import Autocomplete from '@mui/material/Autocomplete';
import { selectClasses, TextField } from '@mui/material';
import debounce from 'lodash/debounce';
function Searchbar() {
const [options, setOptions] = React.useState([]);
const [input, setInput] = React.useState("");
const search = (event, newInputValue) => {
console.log("Debounced Called")
}
const debounced_search = debounce(search, 500)
return (<Autocomplete
id="free-solo"
freeSolo
renderInput={(params) => <TextField {...params} label="Test" />}
inputValue={input}
options={options}
onInputChange={function (event, newInputValue) {
debounced_search(event, newInputValue);
setInput(newInputValue);
console.log("Input Changed")
}}
/>)
}
export default Searchbar
The reason this isn't working for you is that the function component is called again and again every time there is a state change, which means that everything inside it is re-run each time as well, including your call to debounce(). To deal with this issue, React provides a useCallback() hook:
const debounced_search = useCallback(debounce((event, newInputValue) => {
console.log("Debounced Called")
}, 500), [])
Note that I've inlined the search function here because there's no need to re-create it on every render either.
This is working for me:
index.js
import React, { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
App.js
import React from "react";
import debounce from "@icaruk/debounce";
export default function App() {
const [input, setInput] = React.useState("");
const search = (input) => {
console.log(`Debounced Called with ${input}`);
};
return (
<input
id="free-solo"
value={input}
onChange={function (event) {
const value = event.target.value;
debounce(1000, () => search(value));
setInput(value);
console.log(`Input Changed to ${value}`);
}}
/>
);
}
Here is the sandbox:
https://codesandbox.io/s/blissful-water-gojli?file=/src/App.js
If you have any questions about the code feel free to ask, I didn't put any comments but maybe something needs explanation.