Search code examples
reactjsreact-reduxredux-toolkit

Resetting redux state for specific items


I have an initialState like the following:

import { createSlice } from '@reduxjs/toolkit';

const initialBannerContentState = [
    {
        id: '1',
        name: 'bg',
        url: '',
        isSet: false,
        x: 0,
        y: 0
    },
    {
        id: '2',
        name: 'logo',
        url: '',
        isSet: false,
        x: 0,
        y: 0
    }
];

const bannerContentSlice = createSlice({
    name: 'bannerContent',
    initialState: initialBannerContentState,
    reducers: {
        updateBannerContent(state, action) {
            const { id, item, value } = action.payload;
            const existing = state.find((item) => item.id === id);
            if (existing) {
                switch (item) {
                    case 'url':
                        existing.url = value;
                        break;
                    .... // and more
                    default:
                }
            }
        },
        resetBannerContent(state, action) {
            const { id, item } = action.payload;
            const existing = state.find((item) => item.id === id);
            if (existing) {
                switch (item) {
                    case 'bg': // item with id 1
                        initialBannerContentState[id];
                        break;
                    .... // and more
                    default:
                }
            }
        }
    }
});

export const BannerContentActions = bannerContentSlice.actions;

export default bannerContentSlice.reducer;

Then I am using it like:

import { useDispatch } from 'react-redux';

import { BannerContentActions } from '../../store/bannerContent';

const someThing = () => {
    const dispatch = useDispatch();

return (
    <div>
        <Button onClick={
            dispatch(BannerContentActions.updateBannerContent({
                id: '1',
                item: 'bg',
                url: 'someimageurl'
            }));
            dispatch(BannerContentActions.updateBannerContent({
                id: '1',
                item: 'isSet',
                url: true
            }));
        }>
            Setting some image url
        </Button>
        <Button onClick={
            dispatch(BannerContentActions.resetBannerContent({
                id: '1',
                item: 'bg'
            }));
        }>
            Resetting initial data id 1
        </Button>
    </div>
);

export default something;

So what I am trying to do is to reset everything for id 1 to its initial state. The update function does work, but the reset doesn't do anything. Nothing is changed on the id object.

So I am not sure where it goes wrong, most likely its some logic, but I can't figure it out.


Solution

  • It doesn't appear that the resetBannerContent reducer case is mutating the state object or returning a new state object value.

    I'd suggest searching for the index of the matching element object and mutate the state at that index with the initial state value of the same index.

    You also should be dispatching the action within a callback function, not immediately when the button renders, e.g. onClick={() => dispatch(...)} instead of onClick={dispatch(...)}.

    Example:

    resetBannerContent(state, action) {
      const { id, name } = action.payload;
    
      const index = state.findIndex(
        (item) => item.id === id && item.name === name
      );
    
      if (index !== -1) {
        state[index] = initialBannerContentState[index];
      }
    }
    
    <Button
      onClick={() => {
        dispatch(BannerContentActions.resetBannerContent({
          id: '1',
          name: 'bg'
        }));
      }}
    >
      Resetting initial data id 1
    </Button>
    

    Note: If the item.id properties are globally unique you likely don't need to also pass the 'bg' name value.

    resetBannerContent(state, action) {
      const index = state.findIndex((item) => item.id === action.payload);
    
      if (index !== -1) {
        state[index] = initialBannerContentState[index];
      }
    }
    
    <Button onClick={() => dispatch(BannerContentActions.resetBannerContent('1'))}>
      Resetting initial data id 1
    </Button>