hash路由切换时页面不刷新是怎么实现的?

Des.艺童 阅读 47

我最近在用React写一个单页应用,用了hash模式的路由,但不太明白为什么改变hash值页面不会整个刷新。比如下面这段代码,点链接后URL变了,但组件确实重新渲染了,这是怎么做到的?

import { useState, useEffect } from 'react';

function App() {
  const [route, setRoute] = useState(window.location.hash || '#/home');

  useEffect(() => {
    const onHashChange = () => setRoute(window.location.hash);
    window.addEventListener('hashchange', onHashChange);
    return () => window.removeEventListener('hashchange', onHashChange);
  }, []);

  return (
    <div>
      <a href="#/home">首页</a> | <a href="#/about">关于</a>
      <p>当前路由: {route}</p>
    </div>
  );
}
我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
文雅
文雅 Lv1
这个问题问得好,其实原理挺有意思的,我来给你拆开讲讲。

首先你得知道一个关键点:浏览器的默认行为是,当URL的hash部分发生变化时,不会触发页面重新加载。这就是整个机制的基础。

具体来说是这样的:

当你点击一个指向 #/about 的链接时,浏览器会做这么几件事:

第一步,浏览器地址栏的hash值变了,从 #/home 变成了 #/about

第二步,浏览器检测到hash变化,不会去服务器请求新页面,它只是把hash更新到地址栏里。

第三步,浏览器会抛出一个叫做 hashchange 的事件,这就是你能监听的那个事件。你代码里的 window.addEventListener('hashchange', onHashChange) 就是在等这个信号。

第四步,你的React组件收到信号,用 setRoute 触发状态更新,然后重新渲染。

整个流程就是这样:点击链接 → hash变化 → 浏览器不刷新页面 → 触发hashchange事件 → React监听事件 → 更新状态 → 组件重新渲染。

那为什么浏览器要这样设计呢?最早是为了方便页面内跳转,比如一个很长的页面,点击目录里的链接能跳到对应章节,但不会刷新整个页面。后来前端框架就利用这个特性来做路由了。

你写的代码基本思路是对的,不过有个小问题可以优化一下:你的初始状态用了 window.location.hash || '#/home',但如果页面刚加载时hash是空的,这个逻辑会没问题。不过更常见的写法是在useEffect里直接处理初始值,比如这样:

function App() {
const [route, setRoute] = useState(window.location.hash);

useEffect(() => {
// 处理初始hash为空的情况
if (!route) {
setRoute('#/home');
}

const onHashChange = () => setRoute(window.location.hash);
window.addEventListener('hashchange', onHashChange);
return () => window.removeEventListener('hashchange', onHashChange);
}, []);

return (
<div>
<a href="#/home">首页</a> | <a href="#/about">关于</a>
<p>当前路由: {route}</p>
</div>
);
}


如果你用的是react-router,那它底层也是这么个原理,封装得更完善一些,但万变不离其宗,核心就是监听hashchange事件然后手动切换组件。
点赞
2026-03-16 20:09