How to inherit context correctly when using yarn workspaces and react-router-dom v6?

Viewed 260

I have a monorepo using yarn workspaces and lerna. The structure of my app is basically a 'hub' for importing other yarn packages, and what I'd like to be able to do is allow each package that is being imported to define their own Routes. This works fine if the components are imported from the same package, but when they're imported from other yarn packages, the react router context is lost.

I believe the problem is that both packages are imported separate instances of react-router, so the context for Router is not being passed down from the parent to child components. It seems similar to this issue with React context, but I'm not sure if there's a workaround or other suggested way to fix this issue with react router v6.

A simplified example of what I'm trying to achieve is:

// ImportedApp.js
function ImportedApp() {
    return (
        <Routes>
            <Route path="/" element={<div>Root of app</div>} />
            <Route path="testSubSection" element={<div>Sub page of app</div>} />
        </Routes >
    );
}

// App.js
import ImportedApp from 'ImportedApp';

function AppRoutes() {
    return (
        <Routes>
            <Route
                path="/importedApp/*"
                element={
                      <ImportedApp />
                }
            <Route
                path="/"
                element={<div>My App</div>}
            />
        </Routes>
    );
}

In the above example, if ImportedApp.js is in the same package as App.js, there are no problems. But if I have the exact same code and import it from a separate yarn package, I get

Uncaught Error: useRoutes() may be used only in the context of a <Router> component.

I've tried a combination of using alias and nohoist in my package.json but so far nothing is helping me achieve the goal of getting both to share the same library reference.

1 Answers

The fix here was two fold-

First, an alias for both react-router and react-router-dom needed to be added. But the trick was, this alias needed to be added to both the parent and inherited package.

So the parent-package webpack file eventually looks like:

resolve: {
        alias: {
            'react-router-dom': join(__dirname, '..', 'node_modules', 'react-router-dom', '/'),
            'react-router': join(__dirname, '..', 'node_modules', 'react-router', '/'),
        },
        extensions: ['.ts', '.tsx', '.js', '.jsx', '.less', '.css'],
    },

and the inherited package:

resolve: {
        alias: {
            'react-router-dom': join(
                __dirname,
                '..',
                '..',
                'parent-package',
                'node_modules',
                'react-router-dom',
                '/',
            ),
            'react-router': join(
                __dirname,
                '..',
                '..',
                'parent-package',
                'node_modules',
                'react-router',
                '/',
            ),
        },
    },
Related