Refactor React Context (ComponentHtmlMapContext) to Redux to allow for better extensibility

Created on 13 January 2025, 3 months ago

Overview

I initially implemented the HTML to Component map as a React Context in ✨ Leverage HTML comment annotations, remove wrapping div elements Active . I think landing that MR is super important, however @hooroomoo made a very valid point in the MR that there are a few reasons that using Redux instead might be a better choice.

1) It is potentially slightly more performant
2) It is more consistent with the rest of the codebase (the only other use of Context was refactored away already)

Then, in a follow up discussion with the wider team it was realised that, even more excitingly...

3) It would allow the map to be exposed externally to allow for better extensibility. See πŸ“Œ Create extendibility proof of concept that also serves as documentation-by-example Active which makes the Redux store available outside of the React application..

Proposed resolution

Take the ComponentHtmlMapContext.tsx and refactor it into a new Redux Slice that has just one action (replacing the whole map with a new one) that is called when the HTML is received from the server and consumed by the preview overlay components instead of the Context.

This MR is just to perform the refactor, the extensibility can be tackled later.

User interface changes

✨ Feature request
Status

Active

Version

0.0

Component

Page builder

Created by

πŸ‡¬πŸ‡§United Kingdom jessebaker

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @jessebaker
  • πŸ‡ΊπŸ‡ΈUnited States hooroomoo

    Removing PP-1 tag since ✨ Leverage HTML comment annotations, remove wrapping div elements Active got in.

  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • πŸ‡¬πŸ‡§United Kingdom jessebaker

    I've taken a (quick) look at this and hit a bit of a blocker - storing the map in Redux doesn't seem to work. I wrote a slice (which I've pasted below as a starting point should someone else want to pick this up. Maybe I just made a silly mistake, but it seems that fundamentally storing references to the DOM elements in Redux isn't the way to go.

    ChatGPT suggests: While it's technically possible to store a reference to a DOM element in Redux state, it's generally not recommended. Redux state is intended to be serializable and should ideally only contain plain JavaScript objects, arrays, strings, numbers, and booleans.

    import { createAppSlice } from '@/app/createAppSlice';
    import type { PayloadAction } from '@reduxjs/toolkit';
    import type {
      ComponentsMap,
      SlotsMap,
      RegionsMap,
    } from '@/types/AnnotationMaps';
    
    export interface PreviewElementMapSliceState {
      regionsMap: RegionsMap;
      componentsMap: ComponentsMap;
      slotsMap: SlotsMap;
    }
    
    const initialState: PreviewElementMapSliceState = {
      regionsMap: {},
      componentsMap: {},
      slotsMap: {},
    };
    
    type setRegionsMapPayload = RegionsMap;
    type setComponentsMapPayload = ComponentsMap;
    type setSlotsMapPayload = SlotsMap;
    
    export const previewElementMapSlice = createAppSlice({
      name: 'previewElementMap',
      initialState,
      reducers: (create) => ({
        setRegionsMap: create.reducer(
          (state, action: PayloadAction<setRegionsMapPayload>) => {
            state.regionsMap = action.payload;
          },
        ),
        setComponentsMap: create.reducer(
          (state, action: PayloadAction<setComponentsMapPayload>) => {
            state.componentsMap = action.payload;
          },
        ),
        setSlotsMap: create.reducer(
          (state, action: PayloadAction<setSlotsMapPayload>) => {
            state.slotsMap = action.payload;
          },
        ),
      }),
      selectors: {
        selectRegionsMap: (maps): RegionsMap => {
          return maps.regionsMap;
        },
        selectComponentsMap: (maps): ComponentsMap => {
          return maps.componentsMap;
        },
        selectSlotsMap: (maps): SlotsMap => {
          return maps.slotsMap;
        },
      },
    });
    
    export const { setRegionsMap, setComponentsMap, setSlotsMap } =
      previewElementMapSlice.actions;
    export const { selectRegionsMap, selectComponentsMap, selectSlotsMap } =
      previewElementMapSlice.selectors;
    
    
Production build 0.71.5 2024