Reputation: 5466
I am creating a website where the user can type what he is looking for in a search bar.
Initially, I had a problem with the fact that onChange
was one character behind the user search. For example, if the user search for "banana", the search was "banan".
I understood that the problem comes form the fact that setState
is asynchronous.
onChange is one character on delay - Hooks
To avoid this problem, I introduced the useEffect
component in my code. It works.
However now, if the user types some words, the words he types are not displayed immediately inside the search bar. They are displayed after few moments, as if it were a delay between what the user types and what it is displayed.
My searchbar component
export default function SearchBar({handlerSearchBar}) {
const classes = useStyles();
const [searchBarQuery, setSearchBarQuery] = React.useState([""])
function handleChange(event) {
setSearchBarQuery(event.target.value);
console.log(searchBarQuery)
}
useEffect(() => {
console.log("Search message inside useEffect: ", searchBarQuery);
handlerSearchBar(searchBarQuery)
});
return (
<form className={classes.container} noValidate autoComplete="off">
<TextField
required
id="standard-full-width"
label="Searchbar"
style={{ marginLeft: 40, marginRight: 40 }}
placeholder="Write your query"
// helperText="The results will appear below!"
fullWidth
margin="normal"
InputLabelProps={{
shrink: true,
}}
onChange={handleChange}
/>
</form>
);
}
handlerSearchBar function
It a function that is passing the results from my search-bar component to its parents and then, to its grandparents (SearchForm
).
The grandparents SearchForm
is setting one of its state to what is passed via the searchbar handlerSearchBar
function:
function SearchForm() {
const [searchBarQueryParent, setSearchBarQueryParent] = React.useState([""])
function handlerSearchBar(searchBarQuery) {
setSearchBarQueryParent(searchBarQuery)
console.log(searchBarQuery)
}
return (something)
}
My question is: why is the display of the search words so much delayed than the their actual typing?
I think what is happening is that useEffect
is called for each key stroke, and that is what it is so slow.
I tried to call useEffect
on onSubmit
but there is no improvement.
Or it is my handlerSearchBar
function that makes everything slow
Upvotes: 6
Views: 4625
Reputation: 21
I might be a bit late to the game here, but what I did was to use a debounce
function. This will check the input values every 1 sec, and will remove the lag as well
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import debounce from 'lodash.debounce';
import { TextField } from '@material-ui';
function SomeComp(props) {
const [myValue, setMyValue] = useState(null);
const [fetchDataSwitch, setFetchDataSwitch] = useState(false);
// Limit the number of requests sent
const debouncedFetchData = debounce((cb) => {
cb(!fetchDataSwitch);
}, 1000);
useEffect(() => {
debouncedFetchData((res) => {
setFetchDataSwitch(res);
});
}, [myValue]);
useEffect(() => {
// check if input Is valid
// fire API request
return () => {
// Clean up
};
}, [fetchDataSwitch]);
return (
<TextField
InputProps={{
inputProps: { min: 0 }
}}
fullWidth
placeholder={'Max transit time...'}
type={'number'}
value={myValue || ''}
onChange={({ target }) => setMyValue(target.value)}
/>
);
}
SomeComp.propTypes = {};
SomeComp.defaultProps = {};
export default SomeComp;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Upvotes: 0
Reputation: 5466
I resolved it by changing from onChange
to onBlur
.
I am not totally sure why the change works, but it does work.
Upvotes: 3
Reputation: 3620
You might wanna try to make it so that the useEffect
fires only when searchBarQuery
has been updated. i.e. as a callback upon setSearchBarQuery
. You might do;
//...
useEffect(() => {
console.log("Search message inside useEffect: ", searchBarQuery);
handlerSearchBar(searchBarQuery)
}, [searchBarQuery]);
// ...
Note the second argument, an array, in useEffect to make that only run when that item has changed.
Upvotes: 1