admin管理员组

文章数量:1312639

I have a shared (React) ponent library that I'm building. There is a PrivateRoute ponent that I am wanting to include. However, when I import the ponent from the module library into another application, I get an error:

Error: Invariant failed: You should not use <Redirect> outside a <Router>

The PrivateRoute ponent wraps the react-router/Route ponent with authentication logic and redirects unauthenticated requests to login:

ponent-library

import { Route, Redirect } from 'react-router';
/* ... */

class PrivateRoute extends Component {
  /* ... */
  render() {
    const {
      ponent: Comp, authState, loginPath, ...rest
    } = this.props;

    return (
      <Route
        {...rest}
        render={props => authState === SIGNED_IN ? (
          <Comp {...props} />
        ) : (
          <Redirect
            to={{
              pathname: loginPath,
            }}
          />
        )}
      />
    );
  }
}

I then import the ponent into a separate (React) project:

create-react-app

import { Router } from 'react-router';
import { PrivateRoute } from 'ponent-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" ponent={ProtectedView} />
      </Router>
    );
  }
}

This will work as expected if the PrivateRoute ponent is defined in the create-react-app application. However, moving this ponent to the shared library results in the error.

I have tried building the library with webpack output libraryTarget set to monjs2. 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: 'monjs2',
  },
  //...
};

My assumption is that the issue is with building the ponent 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 piled/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?

I have a shared (React) ponent library that I'm building. There is a PrivateRoute ponent that I am wanting to include. However, when I import the ponent from the module library into another application, I get an error:

Error: Invariant failed: You should not use <Redirect> outside a <Router>

The PrivateRoute ponent wraps the react-router/Route ponent with authentication logic and redirects unauthenticated requests to login:

ponent-library

import { Route, Redirect } from 'react-router';
/* ... */

class PrivateRoute extends Component {
  /* ... */
  render() {
    const {
      ponent: Comp, authState, loginPath, ...rest
    } = this.props;

    return (
      <Route
        {...rest}
        render={props => authState === SIGNED_IN ? (
          <Comp {...props} />
        ) : (
          <Redirect
            to={{
              pathname: loginPath,
            }}
          />
        )}
      />
    );
  }
}

I then import the ponent into a separate (React) project:

create-react-app

import { Router } from 'react-router';
import { PrivateRoute } from 'ponent-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" ponent={ProtectedView} />
      </Router>
    );
  }
}

This will work as expected if the PrivateRoute ponent is defined in the create-react-app application. However, moving this ponent to the shared library results in the error.

I have tried building the library with webpack output libraryTarget set to monjs2. 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: 'monjs2',
  },
  //...
};

My assumption is that the issue is with building the ponent 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 piled/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?

Share Improve this question edited Jun 24, 2019 at 15:39 Corey asked Jun 21, 2019 at 17:39 CoreyCorey 5,8182 gold badges25 silver badges37 bronze badges 3
  • Where you are importing Router from ? – Mosè Raguzzini Commented Jun 24, 2019 at 14:42
  • Importing Router from 'react-router'. 'react-router' is a production dependency in the ponent 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 ponent library. – Corey 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 – apokryfos Commented Jun 24, 2019 at 16:22
Add a ment  | 

4 Answers 4

Reset to default 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 ponents and functions. react-router-dom exports DOM-aware ponents, 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./ReactTraining/react-router/issues/4648#issuement-284479720

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 ponent-library was linked via npm link.

The resolution came from this answer: https://stackoverflow./a/38818358/715597

The solution in my case was to link React and React Router in the ponent library to the applications reference of React and React Router:

# link the ponent library
cd my-app
npm link ../ponent-library

# link its copy of React back to the app's React
cd ../ponent-library
npm link ../my-app/node_modules/react
npm link ../my-app/node_modules/react-router

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 ponent (which shows unauthorized or something you want)
}

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

本文标签: javascriptExport reactrouter Redirect from shared component libraryStack Overflow