从库导入时,不变式失败:您不应在<Router>

时间:2020-04-28 22:53:57

标签: reactjs typescript react-router

对于“错误:不变式失败:您不应该在<Route>之外使用<Router>”有很多问题,但是这一点不同,它仅在使用以下组件时出现:返回<Route>的库。

我的目的是在私有库中创建一个<GuardedRoute>组件,我公司的其他人可以使用npm安装该组件。这个新的组件返回一个<Route>,但是首先检查谓词的返回值。如果检查失败,则<Route>将指向某些替代页面组件。一个简单的用例是检查用户是否已通过身份验证。如果是这样,component中的任何内容都会被渲染;否则,将呈现替代页面组件,即登录屏幕。

如果<GuardedRoute>组件位于正在使用它的应用程序中的某个位置,则可以正常工作。但是,如果相同的组件位于库中,并且应用import的{​​{1}}来自库而不是来自其自己的项目目录结构,那么我得到:

<GuardedRoute>

堆栈跟踪没有太大帮助;最新的相关内容正在Error: Invariant failed: You should not use <Route> outside a <Router> 中的ReactDOM.render()上抛出。

该库被编译为JS,然后使用index.tsx安装到应用程序中。

index.tsx

npm i path/to/library/on/my/filesystem

App.tsx

import * as React from 'react';

import ReactDOM from 'react-dom';
import { App } from './App';

import './index.css';



function __init() {
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    document.getElementById('root')
  );
}
__init();

PrivateRoute.tsx

import * as React from 'react';

import {
  Route,
  BrowserRouter,
  Switch
} from 'react-router-dom';

import { ReportDirectoryActivity } from 'components/activities/ReportDirectoryActivity/ReportDirectoryActivity';
import { AuthActivity } from 'components/activities/AuthActivity/AuthActivity';
import { LogoutActivity } from 'components/activities/LogoutActivity/LogoutActivity';
import { PrivateRoute } from 'components/shared/PrivateRoute/PrivateRoute';



export const App: React.FC = () => {
  return (
    <BrowserRouter>
      <Switch>

        <Route
          exact
          path="/auth"
          component={AuthActivity} />

        <Route
          exact
          path="/logout"
          component={LogoutActivity} />

        <PrivateRoute
          exact
          path="/"
          component={ReportDirectoryActivity} />

      </Switch>
    </BrowserRouter>
  );
};

GuardedRoute.tsx(位于库中)

import * as React from 'react';

import {
  RouteProps,
  Redirect
} from 'react-router-dom';

// if this line is changed to refer to an identical component within the app, this works fine
import { GuardedRoute } from 'my-library/GuardedRoute';



export interface IPrivateRouteProps extends RouteProps {}

export const PrivateRoute: React.FC<IPrivateRouteProps> = props => {
  // using a pass-through fnGuard() just to test
  return (
    <GuardedRoute
      {...props}
      fnGuard={() => true}
      elFailure={(
        <Redirect to="/auth" />
      )} />
  );
};

3 个答案:

答案 0 :(得分:0)

库需要在其Webpack配置中指定可以从外部依赖项中使用react-router-dom

将以下内容添加到您的库Webpack配置中

externals: {
     'react': 'react',
    'react-dom': 'react-dom',
    'react-router-dom': 'react-router-dom' // Add this too apart from react
},

答案 1 :(得分:0)

我的猜测是您的库代码抛出错误,因为它没有将路由器组件视为父组件。

也许您可以创建一个GuardedComponent来包装传递的Component而不是扩展路线?这段代码未经测试,只是出于一般目的。

interface IGuardedComponentProps {
  children: React.ReactNode
  fnGuard: () => boolean;
  elFailure: JSX.Element;
}

export const GuardedComponent: React.FC<IGuardedComponentProps> = props => {
  const { children, fnGuard, elFailure } = props;

  return (
    <>{fnGuard() ? elFailure : children}</>
  );
};

然后您将使用它

<Route
  exact
  path="/"
>
  <GuardedComponent
    fnGuard={() => true}
    elFailure={(
      <Redirect to="/auth" />
    )} />
  >
    <ReportDirectoryActivity />
  </GuardedComponent>
</Route>

答案 2 :(得分:-2)

嘿,哈哈。为什么不阅读React Route库的文档?其中写道,您应该在内部使用<Route>组件 <Router>

最简单的方法是将App组件包装到Router文件中的index.tsx中:

import * as React from 'react';

import ReactDOM from 'react-dom';
import { App } from './App';

import './index.css';



function __init() {
  ReactDOM.render(
    <React.StrictMode>
      <Router>
       <App />
      </Router>
    </React.StrictMode>,
    document.getElementById('root')
  );
}
__init();