2022-11-28 - SingleSPA Utility as React component with shared state
Jump to navigation
Jump to search
Overview
Want to have a shared "utility" module using the Single-SPA framework that allows for state (ie a value, not React State) to be queried and updated by micro-frontend applications, and in addition the utility will be a React component so we can pass down and update React State using useContext.
Attempts to understand how this system works as the documentation is sparse and difficult to follow.
General Notes
- code is considered a Single-SPA utility when it is imported in root-config, normally in importmap (browser module). If it is imported in a microfrontend it's global values exist as an instance in that microfrontend only
- so any code imported in root-config is treated like a Utility, except microfrontends which get registered with Single-SPA and can be mounted/unmounted
- eg npm code imported in root-config act as Utilities
- the shared functionality of the Utility comes from variables declared in global scope, which exported functions reference/adjust
- you could adjust values in the globals using exported functions but that would not trigger rendering by components
- A component Utility is simply a react component file (imports React, function has props param, and returns JSX) that is imported in root config
- Component Utilities create an instance of the component whenever used in microfrontend components, each instance has it's own react State objects
- Idea below uses a pubsub object declared in global state to create a global variable shared by all component Utility instances
Notes
- Utilities are global because they have global const/variables which are universal no matter where the function is invoked
- Component state is not global, it exists inside the component, so each component instance has it's own state
- Component instance's state gets passed down through useContext
- We want to move values into a global variable
- But we were using state so it could be passed by useContext
Method
- use rxjs in (component)utility to create a global pubsub object
- inside utility component have a state of the global object (will be a copy for each component instance)
- use setContext to update the component instance's state
- inside utility component have useEffect that publishes the change to the global pubsub object when state (from setContext) changes
- inside utility component have useEffect that subscribes to global pubsub object, when receive msg it updates the local component's state, triggering a re-render
- sending component will probably also trigger subscription, which might result in set state 2 times
- maybe subscription does a deep object comparison to check if state changed, if not, not need to setState
other tabs
- also set localStorage when we change state (from setContext)
- utility component has ?global eventListener that detects localStorage change and publishes the change to the global pubsub object which should update all components in the other tabs
Reference
Looks like there are many pub-sub libraries available to trigger the components when changes are made, we used rxjs as it is supposed to be powerful if we add functionality in future:
rxjs
- https://github.com/filoxo/single-spa-example-rxjs-shared-state
- https://stackoverflow.com/questions/61500732/how-to-share-ui-state-in-single-spa-using-rxjs
- https://www.youtube.com/watch?v=RvRbe0UbcSY