成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

react-router-dom 的 HashRouter 也就這么回事兒

fnngj / 713人閱讀

摘要:要實(shí)現(xiàn)的功能我們使用開發(fā)項(xiàng)目的時(shí)候,基本上是單頁(yè)面應(yīng)用,也就離不開路由。路由看似神秘,當(dāng)我們簡(jiǎn)單的模擬一下它的核心功能后,發(fā)現(xiàn)也就這么回事兒。實(shí)現(xiàn)的邏輯是,返回中跟匹配到的第一個(gè)孩子。

1 要實(shí)現(xiàn)的功能

我們使用React開發(fā)項(xiàng)目的時(shí)候,基本上是單頁(yè)面應(yīng)用,也就離不開路由。路由看似神秘,當(dāng)我們簡(jiǎn)單的模擬一下它的核心功能后,發(fā)現(xiàn)也就這么回事兒。本文就詳細(xì)的介紹一下react-router-dom HashRouter的核心實(shí)現(xiàn)邏輯。

本文實(shí)現(xiàn)的功能主要包含:

HashRouter

Route

Link

MenuLink

Switch

Redirect

2 實(shí)現(xiàn)的邏輯

先不說(shuō)代碼是怎樣寫的,先上圖,讓大家看一下這個(gè)HashRouter到底是個(gè)什么東東:

好吧,肯定有人會(huì)說(shuō)這些圈圈又是什么東東呀,客官不要著急,待我慢慢解釋:

HashRouter是一個(gè)大的容器,它控制著他自己到底渲染成什么樣子,那么它是通過(guò)什么控制的呢,看它的名字就能猜出來(lái),那就是window.location.hash

當(dāng)HashRouter開始渲染的時(shí)候就會(huì)拿它自己身上的pathname屬性跟它肚子里的Routepath進(jìn)行匹配,匹配上的話,就會(huì)渲染Routecomponent對(duì)應(yīng)的組件。

Link是怎樣切換路由的呢,很簡(jiǎn)單,就是通過(guò)this.props.history.push(path)來(lái)改變HashRouter中的pathname屬性,進(jìn)而驅(qū)動(dòng)Route們 進(jìn)行重新渲染,再次匹配我們的路由,最終實(shí)現(xiàn)路由的切換。

介紹了一下簡(jiǎn)單的邏輯,接下來(lái)我們就看一下具體是怎樣實(shí)現(xiàn)的吧,如下圖:

HashRouter是一個(gè)繼承了React.Component的類,這個(gè)類上的state包括location,監(jiān)聽著hash的變化以驅(qū)動(dòng)Route組件的重新渲染,另外還有一個(gè)history屬性,可以切換頁(yè)面的路由。

本文要實(shí)現(xiàn)的功能中包括RouteLink、MenuLinkSwitch、 Redirect,其中Route的是基礎(chǔ)是核心,MenuLink和某些有特定邏輯的渲染都是在Route的基礎(chǔ)上實(shí)現(xiàn)的。

Route組件上可以接收三種變量,包括component、renderchildren,其中render、children是都是函數(shù),render是根據(jù)特定的邏輯渲染元素,children是用來(lái)渲染MenuLink,這兩個(gè)函數(shù)都接收當(dāng)前路由的props,函數(shù)的返回值是要渲染的元素。

Switch實(shí)現(xiàn)的邏輯是,返回children中跟hash匹配到的第一個(gè)“孩子”。

3 具體的代碼邏輯 (1) HashRouter

HashRouterwindow.loacation.hash跟自己的state掛鉤,通過(guò)改變自己的state驅(qū)動(dòng)頁(yè)面的重新渲染。

import React, {Component} from "react";
import PropTypes from "prop-types";

export default class HashRouter extends Component {
    constructor() {
        super();
        this.state = {
            location: {
                pathname: window.location.hash.slice(1) || "/", // 當(dāng)前頁(yè)面的hash值
                state: {}   //保存的狀態(tài)
            }
        };
    }
    
    // 定義上下文的變量類型
    static childContextTypes = {
        location: PropTypes.object,
        history: PropTypes.object
    }
    
    // 定義上下文的變量
    getChildContext() {
        return {
            location: this.state.location,
            history: {
                push: (path) => { // 就是更新 window.hash值
                    if (typeof path === "object") {
                        let {pathname, state} = path;
                        this.setState({
                            location: {
                                ...this.state.location,
                                state // {from: "/profile"}
                            }
                        }, () => {
                            window.location.hash = pathname;
                        })
                    } else {
                        window.location.hash = path;
                    }
                }
            }
        }
    }
    
    render() {
        return this.props.children; // 渲染頁(yè)面元素
    }
    
    componentDidMount() {
        window.location.hash = window.location.hash.slice(1) || "/";
        // 監(jiān)聽window的hash的變化,驅(qū)動(dòng)頁(yè)面的重新刷新
        window.addEventListener("hashchange", () => {
            this.setState({
                location: {
                    ...this.state.location,
                    pathname: window.location.hash.slice(1) || "/"
                }
            });
        })
    }
}
(2) Route

Route的渲染核心邏輯就是將自己的path和當(dāng)前頁(yè)面的hash進(jìn)行匹配,匹配上了就渲染相應(yīng)的元素,匹配不上就什么都不渲染。

import React, {Component} from "react";
import PropTypes from "prop-types";
import pathToRegexp from "path-to-regexp"

export default class Route extends Component {
    // 定義上下文context的類型
    static contextTypes = {
        location: PropTypes.object,
        history: PropTypes.object
    }
    
    render() {
        // 解構(gòu)傳入Route的props
        let {path, component: Component, render, children} = this.props;
        
        // 解構(gòu)上下文的屬性
        let {location, history} = this.context;
        let props = {
            location,
            history
        };
        
        // 將傳入Route的path和當(dāng)前的hash進(jìn)行匹配
        let keys = [];
        let regexp = pathToRegexp(path, keys, {end: false});
        keys = keys.map(key => key.name);
        
        let result = location.pathname.match(regexp);
        
        if (result) { // 匹配上了
            let [url, ...values] = result;
            props.match = {
                path,
                url,
                params: keys.reduce((memo, key, index) => { // 獲取匹配到的參數(shù)
                    memo[key] = values[index];
                    return memo;
                }, {})
            };
            
            if (Component) { // 普通的Route
                return ;
            } else if (render) { // 特定邏輯的渲染
                return render(props);
            } else if (children) { // MenuLink的渲染
                return children(props);
            } else {
                return null;
            }
        } else { // 沒有匹配上
            if (children) { // MenuLink的渲染
                return children(props);
            } else {
                return null;
            }
        }
    }
}
(3) Redirect

Redirect就干了一件事,就是改變HashRouterstate,驅(qū)動(dòng)重新渲染。

import React, {Component} from "react";
import PropTypes from "prop-types";

export default class Redirect extends Component {
    // 定義上下文context的Type
    static contextTypes = {
        history: PropTypes.object
    }
    
    componentDidMount() {
        // 跳轉(zhuǎn)到目標(biāo)路由
        this.context.history.push(this.props.to);
    }
    
    render() {
        return null;
    }
}
(4) MenuLink
import React, {Component} from "react";
import Route from "./Route";
import Link from "./Link"

export default ({to, children}) => {
    // 如果匹配到了,就給當(dāng)前組件一個(gè)激活狀態(tài)的className
    return  (
        
  • {children}
  • ) }/> }
    (5) Link

    Link就是渲染成一個(gè)a標(biāo)簽,然后給一個(gè)點(diǎn)擊事件,點(diǎn)擊的時(shí)候更改HashRouter的狀態(tài),驅(qū)動(dòng)重新渲染。

    import React, {Component} from "react";
    import PropTypes from "prop-types";
    
    export default class Link extends Component {
        static contextTypes = {
            history: PropTypes.object
        }
        
        render() {
            return (
                 this.context.history.push(this.props.to)}>{this.props.children}
            )
        }
    }
    (6) Switch
    import React, {Component} from "react";
    import PropTypes from "prop-types";
    import pathToRegexp from "path-to-regexp";
    
    export default class Switch extends Component {
        static contextTypes = {
            location: PropTypes.object
        }
        
        render() {
            let {pathname} = this.context.location;
            
            let children = this.props.children;
            for (let i = 0, l = children.length; i < l; i++) {
                let child = children[i];
                let path = child.props.path;
                
                if (pathToRegexp(path, [], {end: false}).test(pathname)) {
                    // 將匹配到的第一個(gè)元素返回
                    return child;
                }
            }
            return null
        }
    }
    4 寫在最后

    好了,這幾個(gè)功能介紹完了,你是否對(duì)HashRouter的原理有所了解了呢?本文只是貼出部分代碼,如果有需要請(qǐng)看demo可以手動(dòng)體驗(yàn)一下哦。

    參考文獻(xiàn):

    react-router

    文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94153.html

    相關(guān)文章

    • ReactRouter升級(jí) v2 to v4

      摘要:概述相對(duì)于幾乎是重寫了新版的更偏向于組件化。汲取了很多思想,路由即是組件,使路由更具聲明式,且方便組合。如果你習(xí)慣使用,那么一定會(huì)很快上手新版的。被一分為三。不止是否有意義參考資料遷移到關(guān)注點(diǎn)官方文檔 概述 react-router V4 相對(duì)于react-router V2 or V3 幾乎是重寫了, 新版的react-router更偏向于組件化(everything is comp...

      JasonZhang 評(píng)論0 收藏0
    • react路由淺析

      摘要:瀏覽器端使用的和集成使用時(shí)會(huì)用到中路由分類基于提供的和事件來(lái)保持和的同步。路由剖析在上面的示例中是轉(zhuǎn)發(fā)的樞紐在這個(gè)中轉(zhuǎn)站有很多線路通過(guò)開關(guān)可以啟動(dòng)列車的運(yùn)行乘坐列車就可以發(fā)現(xiàn)新大陸。 引言 在使用react做復(fù)雜的spa開發(fā)中,開發(fā)中必不可少的就是react-router,它使用Lerna管理多個(gè)倉(cāng)庫(kù), 在browser端常使用的幾個(gè)如下所示 react-router 提供了路由的...

      jackzou 評(píng)論0 收藏0
    • 手挽手帶你學(xué)React:三檔 React-router4.x使用

      摘要:我們?cè)趦?nèi)部來(lái)渲染不同的組件我們這里采用哈希路由的方式,鑒于的渲染機(jī)制,我們需要把值綁定進(jìn)入內(nèi)部。 手挽手帶你學(xué)React入門三檔,帶你學(xué)會(huì)使用Reacr-router4.x,開始創(chuàng)建屬于你的React項(xiàng)目 什么是React-router React Router 是一個(gè)基于 React 之上的強(qiáng)大路由庫(kù),它可以讓你向應(yīng)用中快速地添加視圖和數(shù)據(jù)流,同時(shí)保持頁(yè)面與 URL 間的同步。通俗一...

      SunZhaopeng 評(píng)論0 收藏0
    • [ 一起學(xué)React系列 -- 11 ] React-Router4 (1)

      摘要:中的包中的包主要有三個(gè)和。的理念上面提到的理念是一切皆組件以下統(tǒng)一稱組件。從這點(diǎn)來(lái)說(shuō)的確方便了不少,也迎合一切皆組件的理念。組件是中主要的組成單位,可以認(rèn)為是或的路由入口。將該標(biāo)示為嚴(yán)格匹配路由。的屬性追加一條。 2019年不知不覺已經(jīng)過(guò)去19天了,有沒有給自己做個(gè)總結(jié)?有沒有給明年做個(gè)計(jì)劃?當(dāng)然筆者已經(jīng)做好了明年的工作、學(xué)習(xí)計(jì)劃;同時(shí)也包括該系列博客剩下的博文計(jì)劃,目前還剩4篇:分別...

      tinysun1234 評(píng)論0 收藏0
    • react-router v5.x 源碼分析和理解 SPA router 原理

      摘要:一般情況下,都是作為等其他子路由的上層路由,使用了,接收一個(gè)屬性,傳遞給消費(fèi)子組件。創(chuàng)建對(duì)象,兼容老瀏覽器,其他和沒有大區(qū)別總結(jié)分為四個(gè)包,分別為,其中是瀏覽器相關(guān),是相關(guān),是核心也是共同部分,是一些配置相關(guān)。 這篇文章主要講的是分析 react-router 源碼,版本是 v5.x,以及 SPA 路由實(shí)現(xiàn)的原理。 文章首發(fā)地址 單頁(yè)面應(yīng)用都用到了路由 router,目前來(lái)看實(shí)現(xiàn)路由有...

      Harriet666 評(píng)論0 收藏0

    發(fā)表評(píng)論

    0條評(píng)論

    fnngj

    |高級(jí)講師

    TA的文章

    閱讀更多
    最新活動(dòng)
    閱讀需要支付1元查看
    <