How to share context between multiple libraries?

I’m working on a monorepo with a collection of frontend libraries and looking to use a context from one library in another library that would both be used in the same app.

For example, we have library “a”, which contains the context ContextA that is used by some components (call one of them <ComponentA>), and some of the components in library “b” use ContextA as well (call one of them <ComponentB>).

In an application, the components in library “b” are not able to find a provider for ContextA. I believe this is because when the libraries are built and minified, the final variable name for ContextA is different in each build file. I could be wrong on that though, it could also have something to do with scoping.

Is there a way to share context between two libraries?

If the issue is just with minification, is there a way to control the final names just for contexts so they stay the same across libraries? (Using rollup with babel plugin by the way)


Additional information:

My naive approach was just to use a provider for ContextA in the app that both <ComponentA> and <ComponentB> could use.

For example (in the application):

function App() {
    return (
        <ContextA.Provider value={100}>
            <ComponentA/>
            <ComponentB/>
        </ContextA.Provider>
    )
}

However, as mentioned above, I found that the components in library “b” were not able to find the provider for ContextA.

So I turned to a new approach using a dependent context manager that just receives a context value and renders a provider of that context in library “b” so that the components in library “b” can find the context. Like this (in the application):

function App() {
    return (
        <ContextA.Provider value={100}>
            <BContextManager>
                <ComponentA/>
                <ComponentB/>
            </BContextManager>
        </ContextA.Provider>
    )
}

function BContextManager({children}) {
    const contextValue = React.useContext(ContextA);
    return (
        <DependentContextManagerB contextValue={contextValue}>
            {children}
        </DependentContextManagerB>
    )
}

Where <DependentContextManagerB> would look like this (defined in library “b”):

function DependentContextManagerB({contextValue, children}) {
    return (
        <ContextA.Provider value={contextValue}>
            {children}
        </ContextA.Provider>
    )
}

This approach works with global contexts (those with a single provider for the whole app), if a bit clunky. However this approach is too clunky to be feasible with more local contexts (ones where there may be many providers throughout the app).


I’ve seen this question, which seems to be about creating a provider for a context from a library in an application (only deals with one library).

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Found a relevant issue on React’s issues page: Bug: React Context API is not working from custom NPM library

Resolution is to move “b”’s dependency on “a” to a peer dependency (same way React is usually included so that only one instance of React is present).

So if b/package.json looks like this:

{
    "name": "b",
    "dependencies": {
        "a": "^0.0.0"
    }
}

update it to this:

{
    "name": "b",
    "peerDependencies": {
        "a": "^0.0.0"
    }
}

This has the additional benefit of reducing the bundle size for library “b” (in my case fairly significantly: 12% decrease) and the final build size of the application (less significantly but there’s basically 30 lines of code in my test app).


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x