无法读取未定义的属性“历史”(React Router 5 的 useHistory 钩子)

IT技术 reactjs react-router react-hooks react-router-dom react-context
2021-03-29 04:25:28

我正在使用 React Router 的新 useHistory 钩子,它是几周前发布的。我的 React-router 版本是 5.1.2。我的 React 版本是 16.10.1。你可以在底部找到我的代码。

但是,当我从 react-router 导入新的 useHistory 时,出现此错误:

Uncaught TypeError: Cannot read property 'history' of undefined

这是由 React-router 中的这一行引起的

function useHistory() {
  if (process.env.NODE_ENV !== "production") {
    !(typeof useContext === "function") ? process.env.NODE_ENV !== "production" ? invariant(false, "You must use React >= 16.8 in order to use useHistory()") : invariant(false) : void 0;
  }

  return useContext(context).history; <---------------- ERROR IS ON THIS LINE !!!!!!!!!!!!!!!!!
}

由于它与 useContext 相关并且可能与上下文的冲突有问题,我尝试完全删除对 useContext 的所有调用、创建提供程序等。但是,这没有任何作用。用 React v16.8 试过;一样。我不知道是什么导致了这种情况,因为 React 路由器的所有其他功能都可以正常工作。

***请注意,在调用其他 React 路由器挂钩(例如 useLocation 或 useParams)时会发生同样的事情。

有人遇到过这种情况么?任何可能导致这种情况的想法?任何帮助将不胜感激,因为我在网上找不到与此问题相关的任何内容。

import React, {useEffect, useContext} from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Switch, useHistory } from 'react-router'
import { useTranslation } from 'react-i18next';

import lazyLoader from 'CommonApp/components/misc/lazyLoader';
import {AppContext} from 'CommonApp/context/context';

export default function App(props) {
    const { i18n } = useTranslation();
    const { language } = useContext(AppContext);
    let history = useHistory();

    useEffect(() => {
        i18n.changeLanguage(language);
    }, []);

    return(
        <Router>
            <Route path="/">
                <div className={testClass}>HEADER</div>
            </Route>
        </Router>
    )
}

6个回答

这是因为该react-router组件中未设置上下文。由于它<Router>是设置上下文组件,因此您可以useHistory在子组件中使用,但不能在子组件中使用。

这是解决这个问题的一个非常基本的策略:

const AppWrapper = () => {
  return (
    <Router> // Set context
      <App /> // Now App has access to context
    </Router>
  )
}

const App = () => {
  let history = useHistory(); // Works!
...
// Render routes in this component

然后一定要确保使用“包装器”组件而不是App直接使用。

...解决方案可能是抬起路由器。
2021-05-29 04:25:28
谢谢布赖恩。这确实是问题的原因。:)
2021-06-01 04:25:28
在哪里使用AppWrapper
2021-06-02 04:25:28
他们应该只使用useState useContext复杂的东西
2021-06-08 04:25:28

请注意遇到此问题并且已经使用路由器组件包装组件的其他人。确保 Router 和 useHistory 钩子是从同一个包中导入的。当其中一个从 react-router 导入而另一个从 react-router-dom 导入并且这些包的包版本不匹配时,可能会抛出相同的错误。不要同时使用它们,请在此处阅读区别

zomg...谢谢你,非常感谢。如果我可以不止一次支持这个答案,我会的!
2021-05-29 04:25:28

useHistory在您拥有 Routes 的组件中不起作用,因为useHistory所需的上下文尚未设置。

useHistory将适用于您在Router 中声明的任何子组件或组件,但它不适用于Router的父组件或Router组件本身。

解决办法是:

在主(父)组件中

import { BrowserRouter } from "react-router-dom";

<BrowserRouter><App /></BrowserRouter>

在子组件(App)中

import { withRouter } from "react-router-dom";


function App(props) {
    const { i18n } = useTranslation();
    const { language } = useContext(AppContext);
    let history = useHistory();

    useEffect(() => {
        i18n.changeLanguage(language);
    }, []);

    return(

            <Route path="/">
                <div className={testClass}>HEADER</div>
            </Route>

    )
}

export default withRouter(App);
withRouter()似乎不需要。该示例可以显着减少和改进(例如onClick={history.replace(...)})。
2021-06-20 04:25:28

react-router-dom从 5.0.0更新到 ^5.1.2,它已经解决了。您可能会注意到useHistory是在一个子组件中。