I have a shared (React) component library that I'm building. There is a PrivateRoute
component that I am wanting to include. However, when I import the component from the module library into another application, I get an error:
Error: Invariant failed: You should not use <Redirect> outside a <Router>
The PrivateRoute
component wraps the react-router/Route
component with authentication logic and redirects unauthenticated requests to login:
component-library
import { Route, Redirect } from 'react-router';
/* ... */
class PrivateRoute extends Component {
/* ... */
render() {
const {
component: Comp, authState, loginPath, ...rest
} = this.props;
return (
<Route
{...rest}
render={props => authState === SIGNED_IN ? (
<Comp {...props} />
) : (
<Redirect
to={{
pathname: loginPath,
}}
/>
)}
/>
);
}
}
I then import the component into a separate (React) project:
create-react-app
import { Router } from 'react-router';
import { PrivateRoute } from 'component-library';
/* ... */
class App extends Component {
// "history" is passed in via props from the micro frontend controller.
/* ... */
render() {
return (
<Router history={this.props.history}>
{/* ... */}
<PrivateRoute path="/protected" component={ProtectedView} />
</Router>
);
}
}
This will work as expected if the PrivateRoute
component is defined in the create-react-app application. However, moving this component to the shared library results in the error.
I have tried building the library with webpack output libraryTarget
set to commonjs2. But, I've also tried umd. I've also tried with Rollup. All with the same results.
webpack.config.js
module.exports = {
//...
output: {
path: path.resolve(__dirname, 'dist/'),
publicPath: '',
filename: '[name].js',
libraryTarget: 'commonjs2',
},
//...
};
My assumption is that the issue is with building the component library as the Invariant error is thrown when Redirect
is unable to find the RouterContext
. Although the library builds without errors, it seems that importing compiled/built code is a problem.
Could also be two instances of React causing an issue with the Context API. However, react-router
is not using the Context API. It's using the mini-create-react-context
polyfill.
Any thoughts or ideas on how to resolve this?
Suppose we have a path /blog in our app and we updated it to /tutorials so that now if any user tries to navigate to /blog we need to redirect them to /tutorials, we can do it by using a Redirect component provided by the react-router-dom library. In the below code, we first imported the Redirect component from the react-router-dom library.
We no longer support redirecting on the initial render, due to compatibility issues with future versions of React React won't let us change the state in an ancestor component on the initial render w/out warning, so we had to remove the component, as well as the ability to do a navigate () on the initial render.
The Navigate component changes the current location when it's rendered. Copied! In version 6 of react router, the Redirect component is replaced with Navigate. When the Navigate component is rendered, it changes the current location.
First way using the Redirect component. Second way using the history object which is available inside props, passed by the react-router library.
I did finally discover the issue which had little to do with react-router
and more with React
. I found that this error would only show in local development because the component-library
was linked via npm link
.
The resolution came from this answer: https://stackoverflow.com/a/38818358/715597
The solution in my case was to link React and React Router in the component library to the applications reference of React and React Router:
# link the component library
cd my-app
npm link ../component-library
# link its copy of React back to the app's React
cd ../component-library
npm link ../my-app/node_modules/react
npm link ../my-app/node_modules/react-router
You have to import router (assuming you're using V4) from react-router-dom, eg:
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
In v4, react-router exports the core components and functions. react-router-dom exports DOM-aware components, like <Link> (which renders an <a>) and <BrowserRouter> (which interacts with the browser's window.history ).
react-router-dom re-exports all of react-router's exports, so you only need to import from react-router-dom in your project.
Ref: https://github.com/ReactTraining/react-router/issues/4648#issuecomment-284479720
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With