【问题标题】:Cannot read property 'history' of undefined (useHistory hook of React Router 5)无法读取未定义的属性“历史”(React Router 5 的 useHistory 挂钩)
【发布时间】:2020-02-01 21:11:22
【问题描述】:

我正在使用几周前发布的 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>
    )
}

【问题讨论】:

    标签: reactjs react-router react-hooks react-router-dom react-context


    【解决方案1】:

    这是因为react-router 上下文未在该组件中设置。由于它是设置上下文的&lt;Router&gt; 组件,因此您可以在子组件中使用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

    【讨论】:

    • 谢谢布赖恩。这确实是问题的根源。 :)
    • 他们应该只使用useState useContext 只是复杂的东西
    • ...解决办法可能是把路由器抬起来。
    • 在哪里使用AppWrapper
    【解决方案2】:

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

    【讨论】:

    • zomg...谢谢,非常感谢。如果我可以多次支持这个答案,我会的!
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      解决办法是:

      在主(父)组件中

      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(...)})。
      【解决方案5】:

      我将我的 react-router-dom 从 5.0.0 更新到 ^5.1.2 并已解决。您可能会注意到useHistory 在一个子组件中。

      【讨论】:

        【解决方案6】:

        使用浏览器路由器。

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

        如果您使用路由器,则需要为其指定历史记录:

        import {
          Router,
          Route,
          Switch,
        } from 'react-router-dom';
        
        // Ensure you destructure the createBrowserHistory object
        import { createBrowserHistory } from 'history';
        
        const history = createBrowserHistory();
        return (
          <Router history={history} >
            ...
          </Router>
        );
        

        【讨论】:

          【解决方案7】:

          简而言之,您应该将 const history = useHistory(); 移动到您的子组件中

          【讨论】:

            猜你喜欢
            • 2020-03-27
            • 2020-11-24
            • 2019-07-25
            • 2021-12-04
            • 1970-01-01
            • 1970-01-01
            • 2021-07-18
            • 2018-02-04
            • 2023-04-10
            相关资源
            最近更新 更多