Prevent local storage from being changed when filtering in React

Viewed 96

Whenever I dispatch a search action using context and useReducer for an object in an array stored in local storage, it returns the object, but when I delete the search query from the input box, the list is not returned and the page is blank, can anyone help please?

This is my context:

const NotesContext = createContext(null);
const NotesDispatchContext = createContext(null);

const getStoredNotes = (initialNotes = InitialNotes) => {
  return JSON.parse(localStorage.getItem("storedNotes")) || initialNotes;
};

export const NotesProvider = ({ children }) => {
  const [NOTES, dispatch] = useReducer(NotesReducer, getStoredNotes());
  useEffect(() => {
    localStorage.setItem("storedNotes", JSON.stringify(NOTES));
  }, [NOTES]);

  return (
    <NotesContext.Provider value={NOTES}>
      <NotesDispatchContext.Provider value={dispatch}>
        {children}
      </NotesDispatchContext.Provider>
    </NotesContext.Provider>
  );
};

export const useNotesContext = () => {
  return useContext(NotesContext);
};
export const useNotesDispatchContext = () => {
  return useContext(NotesDispatchContext);
};

const App = () => {
  const [query, setQuery] = useState("");
  const dispatch = useNotesDispatchContext();

  useEffect(() => {
    if (query.length !== 0) {
      dispatch({
        type: "searchNotes",
        query: query,
      });
    }
  }, [query]);
  return (
    <div className="container">
      <header>
        <Title title={"Notes"} className={"app_title"} />
        <form className="search_container">
          <span class="material-symbols-outlined">search</span>
          <input
            type="search"
            placeholder="search notes"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
          />
        </form>
      </header>

This is my reducer function

case "searchNotes": {
      [...NOTES].filter((note) =>
        note.title.toLowerCase().includes(action.query)
      );
    }

The function seems to actually remove the all data from the local storage instead of filtering based on the query string.

1 Answers

Issue

When you dispatch searchNotes you are changing NOTES and the blow useEffect runs. So if the filter resulted to an empty array, there would be nothing in localStorage.

useEffect(() => {
  localStorage.setItem("storedNotes", JSON.stringify(NOTES));
}, [NOTES]);

Solution

What you can do is to remove that useEffect in App that has query as dependency and dispatching searchNotes. And filter directly while rendering, something like this:

{
  NOTES.filter((note) => note.title.toLowerCase().includes(query)).map((note, index) => (
    <div key={index}>{note.title}</div>
  ))
}

And at this point you can remove searchNotes case from your reducer.

Related