从共享组件库导出`react-router`重定向

Posted

技术标签:

【中文标题】从共享组件库导出`react-router`重定向【英文标题】:Export `react-router` Redirect from shared component library 【发布时间】:2019-11-04 13:59:48 【问题描述】:

我有一个正在构建的共享(React)组件库。我想要包含一个PrivateRoute 组件。但是,当我将模块库中的组件导入另一个应用程序时,出现错误:

错误:不变式失败:您不应该在 之外使用

PrivateRoute 组件用身份验证逻辑包装了react-router/Route 组件,并将未经身份验证的请求重定向到登录:

组件库

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,
            
          />
        )
      />
    );
  

然后我将组件导入到一个单独的 (React) 项目中:

创建反应应用程序

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>
    );
  

如果在 create-react-app 应用程序中定义了 PrivateRoute 组件,这将按预期工作。但是,将此组件移动到共享库会导致错误。

我尝试将 webpack 输出 libraryTarget 设置为 commonjs2 来构建库。但是,我也尝试过 umd。我也尝试过汇总。所有结果都相同。

webpack.config.js

module.exports = 
  //...
  output: 
    path: path.resolve(__dirname, 'dist/'),
    publicPath: '',
    filename: '[name].js',
    libraryTarget: 'commonjs2',
  ,
  //...
;

我的假设是问题在于构建组件库,因为当 Redirect 无法找到 RouterContext 时会引发 Invariant 错误。虽然库构建没有错误,但导入编译/构建的代码似乎是个问题。

也可能是两个 React 实例导致 Context API 出现问题。但是,react-router 没有使用 Context API。它使用mini-create-react-context polyfill。

关于如何解决这个问题的任何想法或想法?

【问题讨论】:

您从哪里导入路由器? 从“react-router”导入路由器。 'react-router' 是组件库中的生产依赖项。因此,'create-react-app' 并没有将 'react-router' 列为依赖项,而是从 'react-router' 导入 Router 并从组件库中导入 PrivateRoute。 有没有办法让沙箱重现这个?我已经在codesandbox.io/s/a-simple-react-router-v4tutorial-stnxs 尝试过,但我无法做到 【参考方案1】:

您必须从 react-router-dom 导入路由器(假设您使用 V4),例如:

import  BrowserRouter as Router, Route, Link  from "react-router-dom";

在 v4 中,react-router 导出了核心组件和功能。 react-router-dom 导出 DOM 感知组件,例如 ( 呈现一个 ) 和 (它与 浏览器的 window.history )。

react-router-dom 重新导出所有 react-router 的导出,所以你只 需要从项目中的 react-router-dom 导入。

参考:https://github.com/ReactTraining/react-router/issues/4648#issuecomment-284479720

【讨论】:

感谢您的回复。我正在使用Router,因为我有一个独特的情况,我必须用createBrowserHistory 定义历史记录(很像BrowserRouter)。我们有一个微前端架构,历史在注册的应用程序之间共享以维护状态。 是的,但是要管理路由器渲染,无论如何你都需要 react-router-dom,伙计【参考方案2】:

我终于发现了与react-router 关系不大的问题,而与React 关系更大。我发现这个错误只会在本地开发中显示,因为component-library 是通过npm link 链接的。

决议来自这个答案:https://***.com/a/38818358/715597

我的解决方案是将组件库中的 React 和 React Router 链接到 React 和 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

【讨论】:

【参考方案3】:

你不能用函数来做吗

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)

【讨论】:

【参考方案4】:

你只需要从 package.json 中移除依赖 "react-router-dom": "5.0.0" 来修复错误。

【讨论】:

以上是关于从共享组件库导出`react-router`重定向的主要内容,如果未能解决你的问题,请参考以下文章

使用 Jest 和 Enzyme 测试 react-router 重定向

Storybook 中的 React-Router 重定向

如何从 express 重定向到 react-router?

React-Router:将我的 url 从 hashHistory 重定向到 browserHistory

react-router:从组件或存储更改路由

React - 登录到尝试页面后的路由和重定向