You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router 6中useLocation未按预期工作的问题排查

问题根源

你直接调用window.history.pushState属于原生浏览器操作,而React Router的useLocation仅会追踪由React Router自身API触发的路由变更(比如useNavigate钩子、<Link>组件跳转)。这种原生方式的路由修改不会同步到React Router的状态中,因此location对象不会更新,依赖它的useEffect自然不会触发。

方案一:改用React Router官方API(推荐)

React Router v6提供了useNavigate钩子,用它来修改路由的话,React Router会自动同步更新location状态,你的useEffect就能正常响应变化。修改后的代码如下:

import React, { useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

const RandLocation: React.FC = () => {
    const location = useLocation();
    const navigate = useNavigate();

    useEffect(() => {
        console.log('location: ', location);
    }, [location]);
    
    return (
        <div>
            <button 
                onClick={() => {
                    const r = Math.random();
                    // 通过useNavigate修改路由,自动同步React Router状态
                    navigate(`/?rnd=${r}`);
                }}
            >
                Click Me
            </button>
            <br/>
        </div>
    )
}
export default RandLocation;
方案二:自定义原生路由监听(无需React Router路由定义)

如果不想依赖React Router的路由配置,或者必须使用原生pushState,可以自己实现全量路由监听逻辑:

核心思路是重写history.pushState和history.replaceState方法,让它们在调用时触发自定义事件,同时监听浏览器的popstate事件(处理前进/后退),最后封装成自定义钩子供组件使用。

示例代码:

import React, { useEffect, useState } from 'react';

// 自定义钩子:监听所有路由变化(包括pushState、replaceState、前进后退)
const useBrowserLocation = () => {
    const [location, setLocation] = useState(window.location);

    useEffect(() => {
        // 保存原生方法
        const originalPushState = window.history.pushState;
        const originalReplaceState = window.history.replaceState;

        // 重写pushState,调用后触发自定义事件
        window.history.pushState = function(...args) {
            originalPushState.apply(this, args);
            window.dispatchEvent(new Event('locationchange'));
        };

        // 重写replaceState,调用后触发自定义事件
        window.history.replaceState = function(...args) {
            originalReplaceState.apply(this, args);
            window.dispatchEvent(new Event('locationchange'));
        };

        // 处理路由变化的统一逻辑
        const updateLocation = () => {
            setLocation(window.location);
        };

        // 监听原生popstate事件和自定义locationchange事件
        window.addEventListener('popstate', updateLocation);
        window.addEventListener('locationchange', updateLocation);

        // 组件卸载时恢复原生方法并移除监听
        return () => {
            window.history.pushState = originalPushState;
            window.history.replaceState = originalReplaceState;
            window.removeEventListener('popstate', updateLocation);
            window.removeEventListener('locationchange', updateLocation);
        };
    }, []);

    return location;
};

const RandLocation: React.FC = () => {
    const location = useBrowserLocation();

    useEffect(() => {
        console.log('location: ', location);
    }, [location]);
    
    return (
        <div>
            <button 
                onClick={() => {
                    const r = Math.random();
                    window.history.pushState({'rnd': r }, '', '/?rnd=' + r);
                }}
            >
                Click Me
            </button>
            <br/>
        </div>
    )
}
export default RandLocation;

这个方案不需要定义任何React Router路由,就能让组件感知所有类型的路由变化。

内容的提问来源于stack exchange,提问作者BuddyJoe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:55:25