skip to Main Content

This is my notesSlice:

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

const url = "http://localhost:8000/";

const initialState = {
  notices: [],
};

export const getNotices = createAsyncThunk(
  "notices/getNotices",
  async (_name, thunkAPI) => {
    try {
      const resp = await axios(`${url}notices`);
      return resp.data;
    } catch (error) {
      return thunkAPI.rejectWithValue("something went wrong");
    }
  }
);

const noticesSlice = createSlice({
  name: "notices",
  initialState,
  reducers: {
    filterNotices: (state, { payload }) => {
      console.log(state.notices)
      console.log(payload)

      if (payload.searchOption === "Simple") {
        state.notices = state.notices.filter((note) =>
          note.title.toLowerCase().includes(payload.search.toLowerCase())
        );
      } else if (payload.searchOption === "Advanced") {
        state.notices = state.notices.filter(
          (note) =>
            note.description
              .toLowerCase()
              .includes(payload.search.toLowerCase()) ||
            note.tags.filter((tag) => {
              tag.toLowerCase().includes(payload.search.toLowerCase());
            })
        );
      }
    },

  },
  extraReducers: (builder) => {
    builder
      .addCase(getNotices.fulfilled, (state, { payload }) => {
        state.notices = payload;
      })

In payload of filterNotice method, I am sending object with search input and searchOption. How should I search through all notices every time I call filterNotice method? And is this even the correct way to do it?

2

Answers


  1. Here’s the corrected version of your filterNotices reducer:

    filterNotices: (state, { payload }) => {
      const { search, searchOption } = payload;
    
      if (searchOption === "Simple") {
        state.notices = state.notices.filter((note) =>
          note.title.toLowerCase().includes(search.toLowerCase())
        );
      } else if (searchOption === "Advanced") {
        state.notices = state.notices.filter((note) =>
          note.description.toLowerCase().includes(search.toLowerCase()) ||
          note.tags.some(tag => tag.toLowerCase().includes(search.toLowerCase()))
        );
      }
    },
    
    Login or Signup to reply.
  2. Don’t mutate your source of truth by filtering it. The filtered result should be computed/derived "state" from the notices state and the search value.

    If you don’t need to persist the filtered notices

    Store the search type and value in state and use selector functions to compute the derived state.

    const initialState = {
      notices: [],
      searchOption: "Simple",
      searchValue: "",
    };
        
    const noticesSlice = createSlice({
      name: "notices",
      initialState,
      reducers: {
        setSearch: (state, action) => {
          const { searchOption, search } = action.payload;
          state.searchOption = searchOption;
          state.searchValue = search.toLowerCase();
        },
        ...
      },
      ...
    });
    
    export const selectFilteredNotices = state => {
      const { notices, searchOption, searchValue } = state.path.to.notices;
    
      switch(searchOption) {
        case "Simple":
          return notices.filter((note) =>
            note.title.toLowerCase().includes(searchValue)
          );
    
        case "Advanced":
          return notices.filter((note) =>
            note.description.toLowerCase().includes(searchValue) ||
            note.tags.some((tag) => tag.toLowerCase().includes(searchValue))
          );
    
        default:
          return notices;
      }
    };
    

    The UI would dispatch the setSearch action to update the search value and use the useSelector hook and selectFilteredNotices function to selected the filtered notices value.

    const dispatch = useDispatch();
    const filteredNotices = useSelector(selectFilteredNotices);
    
    ...
    
    dispatch(setSearch({ searchOption, search }));
    ...
    

    If you do need to persist the filtered notices in state

    Create a new filteredNotices array in state, and when dispatching the filterNotices action you will filter the untouched state.notices array and return/update the state.filteredNotices array. This leaves the original notices data intact.

    const initialState = {
      notices: [],
      filteredNotices: [],
    };
        
    const noticesSlice = createSlice({
      name: "notices",
      initialState,
      reducers: {
        filterNotices: (state, action) => {
          const { searchOption, search } = action.payload;
          const searchValue = search.toLowerCase();
    
          if (searchOption === "Simple") {
            state.filteredNotices = state.notices.filter((note) =>
              note.title.toLowerCase().includes(searchValue)
            );
          } else if (searchOption === "Advanced") {
            state.filteredNotices = state.notices.filter((note) =>
              note.description.toLowerCase().includes(searchValue) ||
              note.tags.some((tag) => tag.toLowerCase().includes(searchValue))
            );
          }
        },
        ...
      },
      ...
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search