Столкнулся с проблемой в состоянии после фильтрации в моем приложении create-react

Я новичок в реагировании и создаю приложение для ведения заметок, используя реакцию и Firebase. Данные правильно хранятся и извлекаются из Firebase и правильно отображаются в пользовательском интерфейсе.

У меня есть поле ввода на панели навигации для поиска заметки.

проблема, с которой я столкнулся:

когда я ищу конкретную заметку, она фильтруется, но когда я очищаю поле поиска, виден только отфильтрованный элемент.

Это из-за неправильного управления состоянием (если я не ошибаюсь), но я не знаю, как им правильно управлять.

Это мой компонент приложения, из которого я передаю свои заметки, полученные из Firebase, в компонент Navbar.

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.info('Data in App comp: ', notedata);
  return (
    <div className='App'>
      <NavBar noteData = {notedata} setNoteData = {setNoteData} />
      <Header autoFetch = {autoFetch} />
      <Card notes = {notedata} />
    </div>
  );
}

export default App;

И это мой компонент Navbar, где я фильтрую:

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.info('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.info('MyNotes(copied): ', myNotes, ' filterNote: ', filterNote);

    props.setNoteData(searchItem.length > 0 ? filterNote : props.noteData);
  };

  // useEffect(() => {
  //   console.info('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>
  );
}

Я также попробовал эти коды с комментариями.

Это моя консоль, когда я ищу: консоль во время поиска

Это моя консоль, когда я очищаю поле поиска: консоль после пустого поля поиска

Если вы внимательно просмотрите состояния на консоли, вы увидите проблему.

🤔 А знаете ли вы, что...
JavaScript поддерживает объектно-ориентированное программирование.


1
62
2

Ответы:

Вы напрямую обновляете состояние notedata при фильтрации. Поэтому в следующий раз, когда вы измените searchFilter, он отфильтрует последний существующий notedata.

NavBar отвечает только за обновление состояния filterSearch. App отвечает за получение и фильтрацию заметок.

Переместите состояние filterSearch в состояние App. В теле компонента App фильтруйте notedata при каждом изменении filterSearch (или notedata).

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>
  );
}

Решено

Вы напрямую обновляете состояние примечаний при фильтрации. Вам необходимо отфильтровать существующие примечания последнего состояния.