阅读 116

实现一个React-Router

实现一个React-Router

试着自己封装一个react-router

主要用React.createContext进行组件通信封装HashRouter

context.js

  • 这里放跨层级通信的context
import React from 'react';

const {Provider, Consumer} = React.createContext()

export {Provider, Consumer}
复制代码

HashRouter.js

  • 最外层的根组件
  • 用来监听路由变化, 以及提供修改路由方法, 提供给被hashRouter包裹的子组件
import React, { Component } from 'react';
import { Provider } from './context'

export default class HashRouter extends Component {
  constructor() {
    super()
    this.state = {
      location: {
        pathname: window.location.hash.slice(1) || '/'
      },
      history: {}
    }
  }
  componentDidMount() {
    // 默认hash没有时,跳转到/
    window.location.hash = window.location.hash || '/'
    // 监听hash值变化 重新设置状态
    window.addEventListener('hashchange', () => {
      this.setState({
        location: {
          ...this.state.location,
          pathname: window.location.hash.slice(1) || '/'
        }
      })
    })
  }
  render() {
    let value = {
      location: this.state.location,
      history: {
        push(to) {
          window.location.hash = to
        }
      } 
    }
    return (
      <Provider value={value}>
        {this.props.children}
      </Provider>
    );
  }
}
复制代码

Route.js

  • 通过匹配url地址,渲染相应的组件
import React, { Component } from 'react'
import { Consumer } from './context'
const { pathToRegexp } = require("path-to-regexp");

export default class Route extends Component {
  render() {
    console.log('props', this.props);
    
    return (
      <Consumer>
        {
          (state) => {
            console.log(state)
            let {path, component:Component, exact=false} = this.props
            let pathname = state.location.pathname
            // 根据path实现一个正则通过正则匹配
            let reg = pathToRegexp(path, [], {end: exact})
            let result = pathname.match(reg)
            if (result) {
              return <Component></Component>
            }
            
            return null
          }
        }
      </Consumer>
    )
  }
}

复制代码

Link.js

  • 点击link标签, 进行更改路由地址
import React, { Component } from 'react'
import { Consumer } from './context'
export default class Link extends Component {
  render() {
    return (
      <Consumer>
        {
          (state) => {
            return <a onClick={() => {
              state.history.push(this.props.to)
            }}>{this.props.children}</a>
          }
        }
      </Consumer>
    )
  }
}

复制代码

Redirect.js

  • 重定向页面, 当所有页面不匹配的时候跳转到首页
import React, { Component } from 'react';
import { Consumer } from './context'


export default class Redirect extends Component {
  render() {
    return <Consumer>
      {
        (state) => {
          // 重定向就是匹配不到后直接跳到Redirect to属性中
          state.history.push(this.props.to)
          return null
        }
      }
    </Consumer>
  }
}

复制代码

switch.js

  • 只匹配到第一个符合的路由
import React, { Component } from 'react'
import { Consumer } from './context'
const { pathToRegexp } = require("path-to-regexp");

export default class Switch extends Component {
  render() {
    return (
      <Consumer>
        {
          (state) => {
            let pathname = state.location.pathname
            let children = this.props.children
            for (let i = 0; i < children.length; i++) {
              let child = children[i]
              let path = child.props.path || ''
              let reg = pathToRegexp(path, [], {end: false})
              let result = pathname.match(reg)
              if (result) { // switch 匹配成功
                return child
              }
            }
            return null
          }
        }
      </Consumer>
    )
  }
}

复制代码
      <HashRouter>
        <div>
          <div>
            <Link to='/home'>home</Link> &nbsp;
            <Link to='/setting'>setting</Link>&nbsp;
            <Link to='/user'>user</Link>&nbsp;
          </div>
          <div>
            <Switch>
              <Route path='/index' component={Index} />
              <Route path='/home' component={Home} />
              <Route path='/setting' component={Setting} />
              <Route path='/user' component={User} />
              <Redirect to="/"></Redirect>
            </Switch>
          </div>
        </div>
      </HashRouter>
复制代码
文章分类
前端
文章标签