Search code examples
javascriptreactjsreduxredux-toolkit

How to assign specific modal to buttons in a Redux modal component?


I have built a modal component with Redux and Redux toolkit. This is how the component looks

initialState:

const initialsState = { isOpen: false };

export default initialState;

slice:

const modalSlice = createSlice({
  name: "modal",
  initialState,
  reducers: {
    setIsOpen: (state, action) => {
      state.isOpen = action.payload;
    }
  }
})

export const { setIsOpen } = modalSlice.actions;
export default modalSliuce.reducer;

selector:

const modal = (state: RootState) => state.modal;

export const modalSelector = createSelector(
  modal,
  (state) => state.isOpen
);

The modal component itself is quite simple. is just a fixed div with a background and children as props.

I need to use the same modal component for multiple cases with different content, but I'm unsure how to associate each button with the correct modal. When I click on a button, it always opens the first modal instead of the one associated with that button. How can I ensure that each button opens the intended modal?


Solution

  • Instead of a single boolean state value that all modals are referencing you should store discrete state for any modal reference that is being toggled.

    Example:

    Modal slice

    export const initialsState = {
      isOpen: {}
    };
    
    const modalSlice = createSlice({
      name: "modal",
      initialState,
      reducers: {
        setIsOpen: (state, action) => {
          state.isOpen[action.payload.id] = action.payload.isOpen;
        }
      }
    })
    
    export const { setIsOpen } = modalSlice.actions;
    
    export default modalSlice.reducer;
    

    Selectors

    Update/modify the selector to take an extra parameter, a modal id value in this case.

    const modalSelector = (state: RootState) => state.modal;
    
    const isOpenSelector = createSelector(
      [modalSelector],
      (modal) => modal.isOpen,
    );
    
    export const modalIsOpenSelector = createSelector(
      [isOpenSelector, (state, id) => id],
      (isOpen, id) => isOpen[id]
    );
    

    To toggle a specific modal's isOpen value, dispatch the setIsOpen action with a modal id and open status.

    dispatch(setIsOpen({
      id: "modalA",
      isOpen: true
    }));
    
    dispatch(setIsOpen({
      id: "modalA",
      isOpen: false
    }));
    

    To open a specific modal, use the updated/modified modalIsOpenSelector function and pass in the modal id parameter.

    const isOpen = useSelector(state => modalIsOpenSelector(state, "modalA"));