react-router 秉承一切皆元件,因此實現的核心就是BrowserRouter,Route,Link;
BrowserRouter:歷史記錄管理物件history初始化及向下傳遞,location變更監聽;
核心思想: 但凡你想把一個值從上往下傳遞;你就想建立一個上下文;但是建立上下文太麻煩;所以
穿建
一個父元件包圍起來
//建立上下文 相對獨立 Provider Consumerconst Context = React。createContext()//獲取Provider 和 comsumer 一切皆元件的思想const Provider = Context。Providerconst Consumer = Context。Consumer
//工具函式 match (path) 返回match 物件import pathToRegexp from “path-to-regexp”;const cache = {};const cacheLimit = 10000;let cacheCount = 0;// 轉換path為正則和關鍵字陣列// pathToRegexp的作用 detail/:name <==>/detail/:name vue 同樣有function compilePath(path, options) { const cacheKey = `${options。end}${options。strict}${options。sensitive}`; const pathCache = cache[cacheKey] || (cache[cacheKey] = {}); if (pathCache[path]) return pathCache[path]; const keys = []; const regexp = pathToRegexp(path, keys, options); const result = { regexp, keys }; if (cacheCount < cacheLimit) { pathCache[path] = result; cacheCount++; } return result;}/** * 匹配pathname和path。 */function matchPath(pathname, options = {}) { if (typeof options === “string”) options = { path: options }; const { path, exact = false, strict = false, sensitive = false } = options; const paths = []。concat(path); // 轉換path為match return paths。reduce((matched, path) => { if (!path) return null; if (matched) return matched; // 轉換path為正則和佔位符陣列 const { regexp, keys } = compilePath(path, { end: exact, strict, sensitive }); // 獲得正則匹配陣列 const match = regexp。exec(pathname); if (!match) return null; // 結構出匹配url和值陣列 const [url, 。。。values] = match; const isExact = pathname === url; if (exact && !isExact) return null; //match 物件 return { path, // 待匹配path url: path === “/” && url === “” ? “/” : url, // url匹配部分 isExact, // 精確匹配 params: keys。reduce((memo, key, index) => { // 引數 memo[key。name] = values[index]; return memo; }, {}) }; }, null);}export default matchPath;
//很精妙 就考驗基本功import React, { Component } from ‘react’import {createBrowserHistory } from ‘history’import matchPath from ‘。/matchPath’//建立一個上下文儲存history,location 等 這個地方有點像store裡的state似的const RouterContext = React。createContext()//Router: 管理歷史記錄變更,location變更等等,並傳遞給後代class BrowserRouter extends Component { constructor(props){ super(props) // 建立瀏覽器history物件 this。history = createBrowserHistory(this。props) // 建立狀態 管理location this。state = { location:this。history。location } //開啟監聽 下面的所有子元件 都會更新 this。unlisten = this。history。listen(location=>{ this。setState({location}) }) } componentWillUnmount(){ //解除安裝的時候釋放監聽 if(this。unlisten){ this。unlisten() } } render(){ return (
//根據傳參配置(path,render,componet,children 之間有競爭關係的) 渲染出元件class Route extends Component{ render(){ return (
//linkclass Link extends React。Component { handleClick(event, history) { event。preventDefault(); history。push(this。props。to); } render() { const { to, 。。。rest } = this。props; return (
export class MyRouterTest extends Component { render() { return (