Search code examples
reactjsreduxredux-thunkredux-toolkitreselect

A state mutation was detected between dispatches, Redux toolkit and selectors/reselect


I'm having some trouble regarding createSelector and async thunk.

Basically I'm trying to retrieve a list of links, and sort them depending on how many clicks they have, from highest to lowest.

Here is my simplified code.

MainPage.tsx

export const MainPage = (): JSX.Element => {
  const dispatch = useDispatch();
  const allLinks = useSelector(selectLinks);
  
  useEffect(() => {
    dispatch(getLinks());
  }, [dispatch]);

  return (
    <div>
      {allLinks.map((link) => ()} //unrelated logic
    </div>
  );
};

links.actions.ts

export const getLinks = createAsyncThunk(
  "getLinks",
  async () => {
    const links = await axios.get"/links")
    return links;
  },
);

links.slice.ts

const linksSlice = createSlice({
  name: "data",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
    .addCase(
      getLinks.fulfilled,
      (state, action) => {
        state.links = action.payload;
      },
    );
  },
});

links.selectors.ts

const selectLinksState = (state: RootState) => state.links;

export const selectLinks = createSelector(selectLinksState, (state) =>
  state.links.sort((a, b) => b.clickCount - a.clickCount),
);

So this compiles fine, but when I open it in the web browser, I get the following error Error: Invariant failed: A state mutation was detected between dispatches

Does anyone know what I'm doing wrong? I'm pretty sure it's something to do with the selectors because if I sort the links directly after fetching them in the action, it works fine.


Solution

  • So even though Redux toolkit is mutable, I tinkered around with the reselect function and changed it to so:

    export const selectLinks = createSelector(selectLinksState, (state) => {
      const sortedArray = [...state.links].sort(
        (a, b) => b.clickCount - a.clickCount,
      );
      return sortedArray;
    });
    

    My logic was to create a new array, so that it wouldn't cause any mutation problems. It works fine now!