首页 > 解决方案 > 上下文 `router` 在 `Redirect` 中被标记为必需,但其值为 `undefined`

问题描述

依赖项:

react@16.8.4
react-dom@16.8.4
react-router@4.3.1
react-router-dom@4.3.1

我有两个项目。让我们称它们为项目 A 和项目 B。项目 A 是项目 B 的依赖项,并且在代码中多次出现以下行:

if (this.state.redirectToOverview) {
    return <Redirect push to={'/path'}/>;
}

但是每次我想通过使用重定向重定向到另一个页面时,我都会收到以下错误(仅当来自项目 A 的重定向被称为项目 B 的依赖项时才会发生这种情况):

checkPropTypes.js:20 Warning: Failed context type: The context `router` is marked as required in `Redirect`, but its value is `undefined`.
    in Redirect
    in Login (created by LoadableComponent)
    in LoadableComponent (created by Context.Consumer)
    in Route (created by App)
    in Switch (created by App)
    in Router (created by HashRouter)
    in HashRouter (created by App)
    in App
printWarning @ checkPropTypes.js:20
checkPropTypes @ checkPropTypes.js:82
getMaskedContext @ react-dom.development.js:9656
constructClassInstance @ react-dom.development.js:11351
updateClassComponent @ react-dom.development.js:14687
beginWork @ react-dom.development.js:15644
performUnitOfWork @ react-dom.development.js:19312
workLoop @ react-dom.development.js:19352
renderRoot @ react-dom.development.js:19435
performWorkOnRoot @ react-dom.development.js:20342
performWork @ react-dom.development.js:20254
performSyncWork @ react-dom.development.js:20228
requestWork @ react-dom.development.js:20097
scheduleWork @ react-dom.development.js:19911
enqueueSetState @ react-dom.development.js:11169
push../node_modules/applicationA-frontend/node_modules/react/cjs/react.development.js.Component.setState @ react.development.js:335
(anonymous) @ Login.js:92
setTimeout (async)
authenticate @ ClientSideAuthManager.js:9
(anonymous) @ Login.js:91
Promise.then (async)
(anonymous) @ Login.js:89
(anonymous) @ Login.js:67
Promise.then (async)
then @ request-base.js:253
(anonymous) @ Login.js:64
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:270
executeDispatch @ react-dom.development.js:561
executeDispatchesInOrder @ react-dom.development.js:583
executeDispatchesAndRelease @ react-dom.development.js:680
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:688
forEachAccumulated @ react-dom.development.js:662
runEventsInBatch @ react-dom.development.js:816
runExtractedEventsInBatch @ react-dom.development.js:824
handleTopLevel @ react-dom.development.js:4826
batchedUpdates$1 @ react-dom.development.js:20439
batchedUpdates @ react-dom.development.js:2151
dispatchEvent @ react-dom.development.js:4905
(anonymous) @ react-dom.development.js:20490
unstable_runWithPriority @ scheduler.development.js:255
interactiveUpdates$1 @ react-dom.development.js:20489
interactiveUpdates @ react-dom.development.js:2170
dispatchInteractiveEvent @ react-dom.development.js:4882
browser.js:38 Uncaught Error: You should not use <Redirect> outside a <Router>
    at invariant (browser.js:38)
    at Redirect.componentWillMount (Redirect.js:35)
    at callComponentWillMount (react-dom.development.js:11421)
    at mountClassInstance (react-dom.development.js:11514)
    at updateClassComponent (react-dom.development.js:14688)
    at beginWork (react-dom.development.js:15644)
    at performUnitOfWork (react-dom.development.js:19312)
    at workLoop (react-dom.development.js:19352)
    at HTMLUnknownElement.callCallback (react-dom.development.js:149)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:199)
invariant @ browser.js:38
componentWillMount @ Redirect.js:35
callComponentWillMount @ react-dom.development.js:11421
mountClassInstance @ react-dom.development.js:11514
updateClassComponent @ react-dom.development.js:14688
beginWork @ react-dom.development.js:15644
performUnitOfWork @ react-dom.development.js:19312
workLoop @ react-dom.development.js:19352
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
replayUnitOfWork @ react-dom.development.js:18578
renderRoot @ react-dom.development.js:19468
performWorkOnRoot @ react-dom.development.js:20342
performWork @ react-dom.development.js:20254
performSyncWork @ react-dom.development.js:20228
requestWork @ react-dom.development.js:20097
scheduleWork @ react-dom.development.js:19911
enqueueSetState @ react-dom.development.js:11169
push../node_modules/applicationA-frontend/node_modules/react/cjs/react.development.js.Component.setState @ react.development.js:335
(anonymous) @ Login.js:92
setTimeout (async)
authenticate @ ClientSideAuthManager.js:9
(anonymous) @ Login.js:91
Promise.then (async)
(anonymous) @ Login.js:89
(anonymous) @ Login.js:67
Promise.then (async)
then @ request-base.js:253
(anonymous) @ Login.js:64
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:270
executeDispatch @ react-dom.development.js:561
executeDispatchesInOrder @ react-dom.development.js:583
executeDispatchesAndRelease @ react-dom.development.js:680
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:688
forEachAccumulated @ react-dom.development.js:662
runEventsInBatch @ react-dom.development.js:816
runExtractedEventsInBatch @ react-dom.development.js:824
handleTopLevel @ react-dom.development.js:4826
batchedUpdates$1 @ react-dom.development.js:20439
batchedUpdates @ react-dom.development.js:2151
dispatchEvent @ react-dom.development.js:4905
(anonymous) @ react-dom.development.js:20490
unstable_runWithPriority @ scheduler.development.js:255
interactiveUpdates$1 @ react-dom.development.js:20489
interactiveUpdates @ react-dom.development.js:2170
dispatchInteractiveEvent @ react-dom.development.js:4882
react-dom.development.js:17117 The above error occurred in the <Redirect> component:
    in Redirect
    in Login (created by LoadableComponent)
    in LoadableComponent (created by Context.Consumer)
    in Route (created by App)
    in Switch (created by App)
    in Router (created by HashRouter)
    in HashRouter (created by App)
    in App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://..../react-error-boundaries to learn more about error boundaries.

这个消息甚至意味着什么?我根本不知道我做错了什么或在哪里看。

在某些情况下(例如登录)弹出的另一个非常相似的错误消息是:

Warning: Failed context type: The context `router` is marked as required in `Switch`, but its value is `undefined`.
    in Switch
    in Suspense
    in div
    in main
    in div
    in div
    in DefaultLayout (created by ApplicationLayout)
    in ApplicationLayout (created by LoadableComponent)
    in LoadableComponent (created by Context.Consumer)
    in Route (created by PrivateRoute)
    in PrivateRoute (created by App)
    in Switch (created by App)
    in Router (created by HashRouter)
    in HashRouter (created by App)
    in App
printWarning @ checkPropTypes.js:20
checkPropTypes @ checkPropTypes.js:82
getMaskedContext @ react-dom.development.js:9656
constructClassInstance @ react-dom.development.js:11351
updateClassComponent @ react-dom.development.js:14687
beginWork @ react-dom.development.js:15644
performUnitOfWork @ react-dom.development.js:19312
workLoop @ react-dom.development.js:19352
renderRoot @ react-dom.development.js:19435
performWorkOnRoot @ react-dom.development.js:20342
performWork @ react-dom.development.js:20254
performSyncWork @ react-dom.development.js:20228
requestWork @ react-dom.development.js:20097
scheduleWork @ react-dom.development.js:19911
enqueueSetState @ react-dom.development.js:11169
./node_modules/react/cjs/react.development.js.Component.setState @ react.development.js:335
update @ index.js:205
(anonymous) @ index.js:215
Promise.then (async)
_loadModule @ index.js:214
componentWillMount @ index.js:168
callComponentWillMount @ react-dom.development.js:11421
mountClassInstance @ react-dom.development.js:11514
updateClassComponent @ react-dom.development.js:14688
beginWork @ react-dom.development.js:15644
performUnitOfWork @ react-dom.development.js:19312
workLoop @ react-dom.development.js:19352
renderRoot @ react-dom.development.js:19435
performWorkOnRoot @ react-dom.development.js:20342
performWork @ react-dom.development.js:20254
performSyncWork @ react-dom.development.js:20228
requestWork @ react-dom.development.js:20097
scheduleWork @ react-dom.development.js:19911
scheduleRootUpdate @ react-dom.development.js:20572
updateContainerAtExpirationTime @ react-dom.development.js:20600
updateContainer @ react-dom.development.js:20657
./node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:20953
(anonymous) @ react-dom.development.js:21090
unbatchedUpdates @ react-dom.development.js:20459
legacyRenderSubtreeIntoContainer @ react-dom.development.js:21086
render @ react-dom.development.js:21155
./src/index.js @ index.js:7
__webpack_require__ @ bootstrap:766
fn @ bootstrap:129
0 @ bundle.js:30584
__webpack_require__ @ bootstrap:766
(anonymous) @ bootstrap:901
(anonymous) @ bootstrap:901
browser.js:38 Uncaught Error: You should not use <Switch> outside a <Router>
    at invariant (browser.js:38)
    at Switch.componentWillMount (Switch.js:27)
    at callComponentWillMount (react-dom.development.js:11421)
    at mountClassInstance (react-dom.development.js:11514)
    at updateClassComponent (react-dom.development.js:14688)
    at beginWork (react-dom.development.js:15644)
    at performUnitOfWork (react-dom.development.js:19312)
    at workLoop (react-dom.development.js:19352)
    at HTMLUnknownElement.callCallback (react-dom.development.js:149)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:199)
invariant @ browser.js:38
componentWillMount @ Switch.js:27
callComponentWillMount @ react-dom.development.js:11421
mountClassInstance @ react-dom.development.js:11514
updateClassComponent @ react-dom.development.js:14688
beginWork @ react-dom.development.js:15644
performUnitOfWork @ react-dom.development.js:19312
workLoop @ react-dom.development.js:19352
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
replayUnitOfWork @ react-dom.development.js:18578
renderRoot @ react-dom.development.js:19468
performWorkOnRoot @ react-dom.development.js:20342
performWork @ react-dom.development.js:20254
performSyncWork @ react-dom.development.js:20228
requestWork @ react-dom.development.js:20097
scheduleWork @ react-dom.development.js:19911
enqueueSetState @ react-dom.development.js:11169
./node_modules/react/cjs/react.development.js.Component.setState @ react.development.js:335
update @ index.js:205
(anonymous) @ index.js:215
Promise.then (async)
_loadModule @ index.js:214
componentWillMount @ index.js:168
callComponentWillMount @ react-dom.development.js:11421
mountClassInstance @ react-dom.development.js:11514
updateClassComponent @ react-dom.development.js:14688
beginWork @ react-dom.development.js:15644
performUnitOfWork @ react-dom.development.js:19312
workLoop @ react-dom.development.js:19352
renderRoot @ react-dom.development.js:19435
performWorkOnRoot @ react-dom.development.js:20342
performWork @ react-dom.development.js:20254
performSyncWork @ react-dom.development.js:20228
requestWork @ react-dom.development.js:20097
scheduleWork @ react-dom.development.js:19911
scheduleRootUpdate @ react-dom.development.js:20572
updateContainerAtExpirationTime @ react-dom.development.js:20600
updateContainer @ react-dom.development.js:20657
./node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:20953
(anonymous) @ react-dom.development.js:21090
unbatchedUpdates @ react-dom.development.js:20459
legacyRenderSubtreeIntoContainer @ react-dom.development.js:21086
render @ react-dom.development.js:21155
./src/index.js @ index.js:7
__webpack_require__ @ bootstrap:766
fn @ bootstrap:129
0 @ bundle.js:30584
__webpack_require__ @ bootstrap:766
(anonymous) @ bootstrap:901
(anonymous) @ bootstrap:901
react-dom.development.js:17117 The above error occurred in the <Switch> component:
    in Switch
    in Suspense
    in div
    in main
    in div
    in div
    in DefaultLayout (created by ApplicationLayout)
    in ApplicationLayout (created by LoadableComponent)
    in LoadableComponent (created by Context.Consumer)
    in Route (created by PrivateRoute)
    in PrivateRoute (created by App)
    in Switch (created by App)
    in Router (created by HashRouter)
    in HashRouter (created by App)
    in App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://..../react-error-boundaries to learn more about error boundaries.

我真的看不出重定向或切换是如何在路由器之外的。这似乎不是真的。

编辑:

这也可能是相关的:

import React, { Component } from 'react';
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom';
import Loadable from 'react-loadable';
import './App.scss';

const loading = () => <div className="animated fadeIn pt-3 text-center"><div className="spinner"/></div>;

// Containers
const DefaultLayout = Loadable({
  loader: () => import('./containers/DefaultLayout'),
  loading
});

// Pages
const Login = Loadable({
  loader: () => import('./views/Pages/Login'),
  loading
});

const Activation = Loadable({
  loader: () => import('./views/Activation/Activation'),
  loading
});

const Register = Loadable({
  loader: () => import('./views/Pages/Register'),
  loading
});

const Page404 = Loadable({
  loader: () => import('./views/Pages/Page404'),
  loading
});

const Page500 = Loadable({
  loader: () => import('./views/Pages/Page500'),
  loading
});

class App extends Component {

  render() {

    function PrivateRoute ({component: Component, authed, ...rest}) {
      return (
        <Route {...rest} render={props => (
            localStorage.getItem('authStatus')
            ? <Component {...props} />
            : <Redirect to={{ pathname: '/login', state: { from: props.location } }} />
        )} />
      )
    }

    return (
      <HashRouter>
        <Switch>
          <Route exact path="/login" name="Login Page" component={Login} />
          <Route exact path="/activateprofile" name="Activate profile" component={Activation} />
          <Route exact path="/register" name="Register Page" component={Register} />
          <Route exact path="/404" name="Page 404" component={Page404} />
          <Route exact path="/500" name="Page 500" component={Page500} />
          <PrivateRoute path='/' component={DefaultLayout} />
        </Switch>
      </HashRouter>
    );
  }
}

export default App;

编辑2:

DefaultLayout第二条错误消息中提到:

<div>
    <Suspense fallback={this.loading()}>
      <Switch>
         {this.getRoutes().map((route, idx) => {
          return route.component && (this.state.rights.some(e => e.content === route.right) || !route.right ) ? (
            <Route
              key={idx}
              path={route.path}
              exact={route.exact}
              name={route.name}
              render={props => (
                <route.component {...props} />
              )} />
          ) : (null);
        })}
        <Redirect from="/" to="/home" />
     </Switch>
    </Suspense>
  </div>

Login第一个堆栈跟踪中提到的组件中:

if (redirectToReferrer === true) {
    return <Redirect to={from}/>
}

标签: reactjsreact-router

解决方案


问题是项目 A 是项目 B 的依赖项,node_modules当我npm link在这个项目上做时,它有一个文件夹。node_modules当被删除/不存在时,所描述的问题不再发生。

编辑:

实际上,事实证明这不是真正的解决方案。适用于所有项目的解决方案是您必须手动包含react-routerreact-router-dom.


推荐阅读