skip to Main Content

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


  1. You are directly updating the notedata state when you filter. So the next time you change the searchFilter, it would filter the last existing notedata.

    The NavBar is only responsible for updating the filterSearch state. The App is responsible for getting, and filtering the notes.

    Move the filterSearch state to the App. In the body of the App component, filter the notedata whenever filterSearch (or notedata) changes.

    function App() {
      const [notedata, setNoteData] = useState([]);
      const [filterSearch, setFilterSearch] = useState('');
    
      useEffect(() => { // the useEffect calls the api
        // fetch data from firebase.
        const autoFetch = async () => {
          const response = await fetch('https://notes-keeper-react-default-rtdb.firebaseio.com/notes.json');
          const data = await response.json();
    
          setNoteData(Object.values(data)); // convert data to an array
        };
        
        autoFetch();
      }, []);
    
      // filter the notes when the notesData or the search changes
      const filteredNotes = useMemo(() => 
        filterSearch === ''
        ? notedata // don't filter if empty
        : notedata.filter(note =>
            note.title.toLowerCase().includes(filterSearch)
          )
      , [notedata, filterSearch])
      
      return (
        <div className='App'>
          <NavBar 
            filterSearch={filterSearch}
            setFilterSearch={setFilterSearch} 
            />
          <Header />
          <Card notes={filteredNotes} />
        </div>
      );
    }
    
    export default function NavBar({ filterSearch, setFilterSearch }) {
      const filterHandler = event => {
        const searchItem = event.target.value.toLowerCase();
        
        setFilterSearch(searchItem);
      };
    
      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>
      );
    }
    
    Login or Signup to reply.
  2. You are directly updating the notedata state when you filter. You need to filter the last state existing notedata

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search