I created a simple component with a search field and some state to update the users input. In order to (theoretically) improve performance, I wrote a debounce
function to prevent the handleChange
from firing on every keystroke.
e.target.value
is always an empty string when the function fires. I tried to use e.persist()
to make the component remember the value, but it gets lost somewhere. So the <input />
appears always empty.
const ShopSearch = () => {
const [search, setSearch] = React.useState("");
const handleChange = e => {
e.persist();
const value = e.target.value;
setSearch(value);
};
function debounce(func) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), 300);
};
}
return (
<div>
<form role="search">
<input
placeholder="Search for a shop"
value={search}
onChange={debounce(handleChange)}
/>
</form>
<Query url="https://shop-search-api.blabla.com/shopsearch?searchTerm=hemden&page=0">
{({ shops }) =>
shops
.filter(shop =>
search.length > 1
? shop.shopName.toLowerCase().includes(search.toLowerCase())
: false
)
.map(shop => <ShopOverview key={shop.tsID} {...shop} />)
}
</Query>
</div>
);
};
What am I doing wrong? I guess the synthetic event gets lost somewhere because it is not there anymore when the function gets finally executed? Can someone explain it to me or point me to some resources?
You are using debounce function inside the component which makes it re-eveluate everytime when the component renders.
Try keeping it either outside of the Component or in the helper functions.
And also use useCallback hook to have a function which doesn't change on App rerenders
function debounce(func) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), 300);
};
}
const ShopSearch = () => {
const [search, setSearch] = React.useState("");
const handleChange = e => {
e.persist();
const value = e.target.value;
setSearch(value);
};
const debouncedHandleChange = React.useCallback(
debounce(handleChange, 500),
[]
);
return (
<div>
<form role="search">
<input
placeholder="Search for a shop"
value={search}
onChange={debouncedHandleChange}
/>
</form>
<Query url="https://shop-search-api.blabla.com/shopsearch?searchTerm=hemden&page=0">
{({ shops }) =>
shops
.filter(shop =>
search.length > 1
? shop.shopName.toLowerCase().includes(search.toLowerCase())
: false
)
.map(shop => <ShopOverview key={shop.tsID} {...shop} />)
}
</Query>
</div>
);
};