Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

面试官:说说React Router有几种模式?实现原理? #203

Open
huihuiha opened this issue Aug 1, 2021 · 1 comment
Open

面试官:说说React Router有几种模式?实现原理? #203

huihuiha opened this issue Aug 1, 2021 · 1 comment

Comments

@huihuiha
Copy link
Contributor

huihuiha commented Aug 1, 2021

一、是什么

在单页应用中,一个web项目只有一个html页面,一旦页面加载完成之后,就不用因为用户的操作而进行页面的重新加载或者跳转,其特性如下:

  • 改变 url 且不让浏览器像服务器发送请求

  • 在不刷新页面的前提下动态改变浏览器地址栏中的URL地址

其中主要分成了两种模式:

  • hash 模式:在url后面加上#,如http://127.0.0.1:5500/home/#/page1
  • history 模式:允许操作浏览器的曾经在标签页或者框架里访问的会话历史记录

二、使用

React Router对应的hash模式和history模式对应的组件为:

  • HashRouter
  • BrowserRouter

这两个组件的使用都十分的简单,作为最顶层组件包裹其他组件,如下所示

// 1.import { BrowserRouter as Router } from "react-router-dom";
// 2.import { HashRouter as Router } from "react-router-dom";

import React from 'react';
import {
  BrowserRouter as Router,
  // HashRouter as Router  
  Switch,
  Route,
} from "react-router-dom";
import Home from './pages/Home';
import Login from './pages/Login';
import Backend from './pages/Backend';
import Admin from './pages/Admin';


function App() {
  return (
    <Router>
        <Route path="/login" component={Login}/>
        <Route path="/backend" component={Backend}/>
        <Route path="/admin" component={Admin}/>
        <Route path="/" component={Home}/>
    </Router>
  );
}

export default App;

三、实现原理

路由描述了 URLUI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)

下面以hash模式为例子,改变hash值并不会导致浏览器向服务器发送请求,浏览器不发出请求,也就不会刷新页面

hash 值改变,触发全局 window 对象上的 hashchange 事件。所以 hash 模式路由就是利用 hashchange 事件监听 URL 的变化,从而进行 DOM 操作来模拟页面跳转

react-router也是基于这个特性实现路由的跳转

下面以HashRouter组件分析进行展开:

HashRouter

HashRouter包裹了整应用,

通过window.addEventListener('hashChange',callback)监听hash值的变化,并传递给其嵌套的组件

然后通过contextlocation数据往后代组件传递,如下:

import React, { Component } from 'react';
import { Provider } from './context'
// 该组件下Api提供给子组件使用
class HashRouter extends Component {
  constructor() {
    super()
    this.state = {
      location: {
        pathname: window.location.hash.slice(1) || '/'
      }
    }
  }
  // url路径变化 改变location
  componentDidMount() {
    window.location.hash = window.location.hash || '/'
    window.addEventListener('hashchange', () => {
      this.setState({
        location: {
          ...this.state.location,
          pathname: window.location.hash.slice(1) || '/'
        }
      }, () => console.log(this.state.location))
    })
  }
  render() {
    let value = {
      location: this.state.location
    }
    return (
      <Provider value={value}>
        {
          this.props.children
        }
      </Provider>
    );
  }
}

export default HashRouter;

Router

Router组件主要做的是通过BrowserRouter传过来的当前值,通过props传进来的pathcontext传进来的pathname进行匹配,然后决定是否执行渲染组件

import React, { Component } from 'react';
import { Consumer } from './context'
const { pathToRegexp } = require("path-to-regexp");
class Route extends Component {
  render() {
    return (
      <Consumer>
        {
          state => {
            console.log(state)
            let {path, component: Component} = this.props
            let pathname = state.location.pathname
            let reg = pathToRegexp(path, [], {end: false})
            // 判断当前path是否包含pathname
            if(pathname.match(reg)) {
              return <Component></Component>
            }
            return null
          }
        }
      </Consumer>
    );
  }
}
export default Route;

参考文献

@Mebius1916
Copy link

Mebius1916 commented Nov 11, 2024

1. BrowserRouter

模式:

  • 使用 HTML5 的 history API 提供干净的 URL(不带哈希符号)。
  • URL 看起来类似于常规的网页 URL,例如 /about/contact

实现原理:

  • BrowserRouter 利用 history.pushStatehistory.replaceState 方法来操作 URL,而不会引起页面刷新。
  • 在用户操作浏览器的前进和后退按钮时,popstate 事件会被触发,BrowserRouter 会监听这个事件,并根据当前 URL 渲染相应的 React 组件。
  • 通过 Link 组件或编程式导航来改变应用的路径,触发组件的重新渲染。

2. HashRouter

模式:

  • 使用 URL 的哈希部分(即 # 后面的部分)来保持 UI 的状态。
  • URL 看起来像 /#/about/#/contact

实现原理:

  • HashRouter 利用 window.location.hash 属性来读取和设置 URL 的哈希值。
  • 由于哈希的变化不会导致浏览器重新加载页面,因此它不会局限于服务器端路由。
  • HashRouter 监听 hashchange 事件,当哈希发生变化时,更新组件以匹配新路径。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants