手寫React Router

原理

目前常見的路由分爲兩種,HashRouterBrowserRouterhtml

HashRouter

hash路由的方式主要是經過改變hash值來改變url,由於只是改變hash,因此並不會觸發頁面刷新,很適合用在單頁應用局部更新,window提供監聽hashChange方法來監聽hash值的改變去更新咱們的單頁react

window.addEventListener('hashchange', function(e) {
  console.log('hashchange', e)
  // 更新頁面
})
複製代碼
BrowserRouter

history是h5新出的api,讓咱們能夠在改變url而不刷新頁面,主要的幾個api是:git

  1. History.back(): 返回瀏覽器會話歷史中的上一頁,跟瀏覽器的回退按鈕功能相同github

  2. History.forward():指向瀏覽器會話歷史中的下一頁,跟瀏覽器的前進按鈕相同。api

  3. History.go(): 能夠跳轉到瀏覽器會話歷史中的指定的某一個記錄頁。瀏覽器

  4. History.pushState():pushState能夠將給定的數據壓入到瀏覽器會話歷史棧中,該方法接收3個參數,對象,title和一串url。pushState後會改變當前頁面url,可是不會伴隨着刷新。bash

  5. History.replaceState():replaceState將當前的會話頁面的url替換成指定的數據,replaceState後也會改變當前頁面的url,可是也不會刷新頁面。ide

  6. 以上只是實現改變url不刷新頁面,咱們還須要監聽用戶前進後退的變化。popstate是history的一個監聽事件,能夠監聽history的變化學習

好了,基本上就是這個原理ui

實現

實現部分主要是利用reactcontext api來存儲路由信息,子組件根據context值去渲染,代碼是由hook實現,不瞭解的,看以前,學習一下React Hook,下面咱們來實現一下BrowserRouter

BrowserRouter

import React, { useState } from "react";
  
let set; // 保存setUrl,由於監聽事件我們值加入一次,因此放外面
function popstate(e) {
  set(window.location.pathname);
}
// 建立context
export const RouterContext = React.createContext(window.location.pathname);

export default function({ children }) {
  const [url, setUrl] = useState(window.location.pathname);
  set = setUrl;

  window.addEventListener("popstate", popstate);

  const router = {
    history: {
      push: function(url, state, title) {
        window.history.pushState(state, title, url);
        setUrl(url);
      },
      replace: function(url, state, title) {
        window.history.replaceState(state, title, url);
        setUrl(url);
      },
      // 下面也須要嵌入setUrl,暫不處理
      go: window.history.go,
      goBack: window.history.back,
      goForward: window.history.forward,
      length: window.history.length
    },
    url: url
  };

  return (
    <RouterContext.Provider value={router}>{children}</RouterContext.Provider>
  );
}
複製代碼

Route

import React, { useContext } from "react";
import { RouterContext } from "./BrowserRouter";

function Route({ component, path }) {
  // 獲取context
  const { history, url } = useContext(RouterContext);
  const match = {
    path,
    url
  };
  const Component = component;
  return url === path && <Component history={history} match={match} />;
}

export default Route;
複製代碼

Link

import React, { useContext } from "react";
import { RouterContext } from "./BrowserRouter";
import styled from "styled-components";

const A = styled.a`
  text-decoration: none;
  padding: 5px;
`;

function Link({ children, to }) {
  const { history } = useContext(RouterContext);
  const onClick = e => {
    e.preventDefault();
    history.push(to);
  };
  return (
    <A href={to} onClick={onClick}>
      {children}
    </A>
  );
}

export default Link;
複製代碼

總結

查看Github源碼 其實很簡單的一個東西,瞭解原理很容易實現,看了這篇文章,你也能夠試着去實現一下HashRouter.

相關文章
相關標籤/搜索