12

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?

3
  • Where you are importing Router from ? Commented Jun 24, 2019 at 14:42
  • Importing Router from 'react-router'. 'react-router' is a production dependency in the component library. So, the 'create-react-app' does not list 'react-router' as a dependency, but imports the Router from 'react-router' and PrivateRoute from the component library. Commented Jun 24, 2019 at 14:58
  • Is there a way to get a sandbox that reproduces this? I've tried at codesandbox.io/s/a-simple-react-router-v4tutorial-stnxs but I can't manage to Commented Jun 24, 2019 at 16:22

4 Answers 4

3
+50

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the response. I'm using Router because I have a unique situation where I have to define the history with createBrowserHistory (much like BrowserRouter). We have a micro frontend architecture and the history is shared between the registered applications to maintain state.
Yes but to manage router render you need anyway react-router-dom, mate
1

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

Comments

0

Can't you do it using a function

if(authState === SIGNED_IN){
   return <Route
        {...rest}
        render={<Comp {...props} />
        />
}else{
   // here you can use window.location 
   // or 
   // render a different component (which shows unauthorized or something you want)
}

Comments

-1

you only needed to remove dependency "react-router-dom": "5.0.0" from package.json to fix the error.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.