React -- 自己实现一个react-router-dom里面的一些组件(简单路由)

本次主要实现的是Hash路由,也就是监听/#/后面的hash值得变化。

使用过react的都知道,this.props上面有一个比较重要的属性location,match, history等,这一次我们实现里面的几个简单属性,用于完成路由,如下:

location: {pathname } history: { push}  match: { url, path, params}

由于设计到父子组件传递,所有我们用到了context.

对于hash的改变我们可以在window注册hashchange事件。

HashRouter组件

import React, { Component } from "react";
import RouteContext from "./RouteContext";
 

export default class HashRouter extends Component {
    constructor (props) {
        super(props);
        this.state = { location: {}, history: {}, match: {}};
        this.handleHash = this.handleHash.bind(this);
    }
    handleHash () {
        const hash = window.location.hash.slice(1); //获取#后面的路径
        this.setState( (perProps, perState) => {
            return {
                ...perState,
                location: {
                   ...perState.location,
                   pathname: hash  //也就是pathname里面的值
                },
                history: {
                    ...perState.history,
                    push: (event, pathname) => { //push函数很简单,就是改变当前window下面的hash
                        event.preventDefault();
                        window.location.hash = pathname;
                    }
                }
            }
        })
    }
    componentDidMount () {
       // window.location.hash = window.location.hash || "/";
        this.handleHash();
        window.addEventListener("hashchange", () => { //在window上注册hashchange事件
            this.handleHash();
        } )
         
    }
    render () {
        return ( 
            { this.props.children } 
        )
    }
}

Route组件 

使用了pathtoregexp用正则来处理hash(比如这样的/a/b/:id)

import React, { Component } from "react";
import RouteContext from "./RouteContext";
import pathToRegexp from "path-to-regexp";

export default class Route extends Component {
    constructor (props) {
        super(props);
        const { src } = this.props;
        this.key = [];
        this.regexp = pathToRegexp(src, this.key, { end: false }) //生成正则
        this.key = this.key.map( (user) => (user.name) ); //获取:id :name这样的
    }

    render () {
        const { src, component: Component } = this.props;

        return (
            
               {
                   (context) => {
                       const { pathname } = context.location;
                       let result;
                       if (pathname)  result = pathname.match(this.regexp); //看是否匹配成功
    
                       if (result) {
                           const [url, ...values] = result; //如果成功那么就把match里面的一些属性生成,
                           const match = {
                               ...context.match,
                               url,
                               path: src,
                               params: this.key.reduce((memo, v, index) => {
                                   memo[v]  = values[index];
                                    
                                   return memo;
                               }, {})
                           }//返回component属性里面的组件
                           return 
                       } else {
                           return null;
                       }
                    //    if ( pathname && (pathname === src || pathname.startsWith(src))) return ;
                    //    else return null;
                   }
               } 
            
        )
    }
}

Link组件

import React, { Component } from "react";
import RouteContext from "./RouteContext";
export default class Link extends Component {

    render () {
        return (
            
            {
                (context) => {
                    const  hashPush  = context.history.push; //简单就是一个a标签,然后就是利用history.push来跳转
                    return  { hashPush(e, this.props.to)} } >{ this.props.children }
                }
            }    
            
        )
         
    }
}

Switch组件


import React, { Component } from "react";
import RouteContext from "./RouteContext";
import pathToRegexp from "path-to-regexp";
export default class Switch extends Component {//作用匹配唯一一个路由

    render () {
        const children = this.props.children;
        return (
           
               {
                   (context) => {
                       const { pathname } = context.location;
                       for (let i = 0; i < children.length; i++) { //如果匹配到第一个就返回
                           let child = children[i];
                           const { src } = child.props;
                           const regexp = pathToRegexp(src, [], { end: false });
                           if (regexp.test(pathname)) return child;
                       }
                   }
               }
           
        )
    }
}

差不多了,就可以实现一个简单的路由。

React -- 自己实现一个react-router-dom里面的一些组件(简单路由)_第1张图片React -- 自己实现一个react-router-dom里面的一些组件(简单路由)_第2张图片

输入一个id,然后一个名字,提交后会存入localStorage,点击用户展示就显示所有人的ID,然后点击ID就会进入用户页面。

React -- 自己实现一个react-router-dom里面的一些组件(简单路由)_第3张图片

 

你可能感兴趣的:(React)