I am new to react and I am making Note-keeping application using react and firebase. Data is properly store and retrieve from firebase and rendering properly on UI.
I have an Input filed on Navbar to searching for a note.
problem i am facing:
when i search for particular note it got filtered, but when i do empty my search filed only filtered item is visible.
Its due to improper state management-(if i am not wrong), but i don’t how to manage it properly.
This is my App component from where i am passing my Notes which is fetch from firebase to the Navbar component.
import './App.css';
import NavBar from './components/Navbar/NavBar';
import Header from './components/Header/Header';
import Card from './components/Card/Card';
import { useEffect, useState } from 'react';
function App() {
const [notedata, setNoteData] = useState([]);
// fetch data from firebase.
let autoFetch = async () => {
const response = await fetch('https://notes-keeper-react-default-rtdb.firebaseio.com/notes.json');
const data = await response.json();
let notesArr = [];
Object.keys(data).map((key) => {
notesArr.push(data[key]);
});
setNoteData(notesArr);
};
useEffect(() => {
autoFetch();
}, []);
console.log('Data in App comp: ', notedata);
return (
<div className='App'>
<NavBar noteData={notedata} setNoteData={setNoteData} />
<Header autoFetch={autoFetch} />
<Card notes={notedata} />
</div>
);
}
export default App;
And this is my Navbar component where i am filtering:
import { useState, useEffect } from 'react';
import classes from './NavBar.module.css';
export default function NavBar(props) {
const [filterSearch, setFilterSearch] = useState('');
const myNotes = [...props.noteData];
const filterHandler = (event) => {
let searchItem = event.target.value.toLowerCase();
setFilterSearch(searchItem);
console.log('searching for: ', searchItem);
// if (searchItem.length > 0) {
// const filterNote = props.noteData.filter((note) => note.title.toLowerCase().includes(filterSearch));
// props.setNoteData(filterNote);
// } else {
// props.setNoteData(props.noteData);
// }
const filterNote = myNotes.filter((note) => note.title.toLowerCase().includes(searchItem));
console.log('MyNotes(copied): ', myNotes, ' filterNote: ', filterNote);
props.setNoteData(searchItem.length > 0 ? filterNote : props.noteData);
};
// useEffect(() => {
// console.log('inside filter useEffect');
// const filterNote = filterSearch
// ? props.noteData.filter((note) => note.title.toLowerCase().includes(filterSearch.toLowerCase()))
// : props.noteData;
// props.setNoteData(filterNote);
// }, [filterSearch]);
return (
<div className='container'>
<nav>
<div className={classes['nav-heading']}>
<h1>Notes</h1>
</div>
<div className={classes['nav-search']}>
<div className={classes['nav-controls']}>
<input
type='text'
name='search'
id='search'
placeholder='Search for Title'
value={filterSearch}
onChange={filterHandler}
/>
</div>
</div>
</nav>
</div>
);
}
I also tried these Commented codes.
This is my console when i am searching:
console during search
This is my console when i do empty my search field:
console after empty search field
If you carefully see the states on console, you will see the problem.
2
Answers
You are directly updating the
notedata
state when you filter. So the next time you change thesearchFilter
, it would filter the last existingnotedata
.The
NavBar
is only responsible for updating thefilterSearch
state. TheApp
is responsible for getting, and filtering the notes.Move the
filterSearch
state to theApp
. In the body of theApp
component, filter thenotedata
wheneverfilterSearch
(ornotedata
) changes.You are directly updating the notedata state when you filter. You need to filter the last state existing notedata