设置 React Router 历史监听器的正确位置

Proper place to setup React Router history listener

我正在尝试在最顶层设置一个历史监听器,以便每次位置发生变化时,都会执行一些代码(Google 在我的案例中是分析跟踪)。

目前,我的 App.js 看起来像这样:

    render() {
        return (
            <BrowserRouter>
                <Switch>
                    <Route path="/" exact component={Home}/>
                    <Route path="/" component={MainLayout}/>
                </Switch>
            </BrowserRouter>
        );
    }

据我了解,我只能在BrowserRouter里面使用history,但是它只能有一个child,所以我只能把它放在Switch里面,但是我必须将它放在 Switch 下的每个组件中,我不能这样做,因为我只希望它 运行 一次。如果我只是在 Switch 下添加自定义组件而不将其包装到 Router 中,则没有历史记录。

我应该更改什么才能使其正常工作?是否可以在 App.js 代码中获取 history 的实例?是否可以使用自定义组件或 HOC 来实现?

可以使用 history 包,而不是依赖 React router 创建的默认包。

例如,使用history.listen:

  history.listen((location) => {
    ReactGA.pageview(location.pathname + window.location.search);
  });

在我的示例中,我使用 react-ga 作为跨项目标准化我们的 GA 工具的一种方式。

您需要添加一个 Route,它将无条件呈现。 尝试这样的事情:

render() {
    return (
        <BrowserRouter>
            <React.Fragment>
                <Route component={HistoryListenerComponent}/>
                <Switch>
                    <Route path="/" exact component={Home}/>
                    <Route path="/" component={MainLayout}/>
                </Switch>
            </React.Fragment>
        </BrowserRouter>
    );
}

所以 HistoryListenerComponent 总是被渲染,你可以 listen 从它的 componentDidMount.

发现最简单的选项是更新组件 -- https://github.com/pshrmn/rrc/blob/master/docs/OnUpdate.md

以下是对我有用的方法:

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

现在只需像这样用 withRouter 包裹你使用 React-ga 的组件:

    componentDidMount=()=>{
         ReactGa.initialize('00000'); //enter id
        ReactGa.pageview(window.location.pathname + window.location.search);
        
        this.props.history.listen(location => {
            ReactGa.set({ page: location.pathname }); // Update the user's current page
            ReactGa.pageview(location.pathname); // Record a pageview for the given page
        });
    }
    render (){
       return (
         <Switch>
<Route ....>
.....
<Switch>
     );
     }
export default withRouter(ComponentName)

记住没有包装 withRouter ,你不能使用 this.props.history 属性。 您不能将自定义历史侦听器用于 BrowserRouter 组件。它有一个内置的历史道具(即 this.props.history)。