I'm currently fetching data from my db but for the simplicity of this Q, I have decided to manually create an example with fake data.
I'm building a search-bar for my users to look through all of the data coming from db and everything seems to be working fine when looking for a specific document, however, I want to reset the state to its original data when the input is empty.
This is what I've tried so far but with no success. Am I missing something?
const objects = [
{
_id: 0,
title: 'Title One',
},
{
_id: 1,
title: 'Title Two',
},
{
_id: 2,
title: 'Title Three',
},
]
const [keyword, setKeyword] = useState('')
const [list, setList] = useState([]);
useEffect(() => {
setList(objects);
}, [objects]);
const handleChange = () => (e) => {
e.preventDefault()
setKeyword(e.target.value)
if (keyword !== '') {
const result = objects.filter((object) => {
return object.title.toLowerCase().startsWith(keyword.toLowerCase())
})
setList(result)
} else {
// THIS IS WHERE THE PROBLEM RESIDES...
console.log('Original data')
setList(objects)
}
}
CodePudding user response:
What you're doing wrong is in these lines
setKeyword(e.target.value)
if (keyword !== '') {
The state is updated asynchronously, and the value of the keyword
will be old.
What you can do is update the state in handleChange
and then have a separate useEffect
to update the results:
const [keyword, setKeyword] = useState('')
const [list, setList] = useState([]);
useEffect(() => {
setList(objects);
}, [objects]);
useEffect(() => {
if (keyword !== '') {
const result = objects.filter((object) => {
return object.title.toLowerCase().startsWith(keyword.toLowerCase())
})
setList(result)
} else {
// THIS IS WHERE THE PROBLEM RESIDES...
console.log('Original data')
setList(objects)
}
}, [keyword]);
const handleChange = () => (e) => {
e.preventDefault()
setKeyword(e.target.value)
}
CodePudding user response:
State setters are asynchronous. The code following a state update (your if(keyword)
may be run before the state update is complete (setKeyword
)
Your code may be simplified if you merge keyword
& list
in a single object.
var [searchState, setSearchState] = useState({keyword: '', list: objects.slice());
handleChange=(evt)=>{
let word = evt.target.value;
let wordLower= word.toLowerCase();
setSearchState({
keyword:word,
list: word?objects.filter(o=>o.title.toLowerCase().startsWith(wordLowerCase):objects.slice()
});
};
Or you can use class based component where the state is a single object.