reactRouter实现原理

34 阅读1分钟

reactRouter实现原理

阅读此文档需掌握一下知识点:

  • React Hooks
  • History API

index.js

import { BrowserRouter, Route, RouterContext } from './router'

function Home() {
  return <h2>Home</h2>
}

function About() {
  return <h2>About</h2>
}

function Users() {
  return <h2>Users</h2>
}

function App() {
  return (
    <BrowserRouter>
      <RouterContext.Consumer>
        {() => (
          <>
            <button onclick={()=>{ router.goPath('/')}}>home</button>
            <button onclick={()=>{ router.goPath('/about')}}>about</button>
            <button onclick={()=>{ router.goPath('/users')}}>users</button>

            <Route path="/" component={<Home />} />
            <Route path="/about" component={<About />} />
            <Route path="/users" component={<Users />} />
          </>
        )}
      </RouterContext.Consumer>
    </BrowserRouter>
  ) 
}

export default App

router.js

import React,{ useState, useEffect } from 'react'

export const RouterContext = React.createContext()

// BrowserRouter组件 
export function BrowserRouter(props) {
  // 初始化数据
  const [path, setPath] = useState(window.location.pathname || '/')

  useEffect(() => {
    // 监听浏览器路由前进后退事件
    window.addEventListener('popstate', handlePopstate)

    // 卸载监听
    return () => {
      window.removeEventListener('popstate', handlePopstate)
    }
  })
  function handlePopstate() {
    const { pathname } = window.location
    setPath(pathname)
  }

  // 跳转方法
  function goPath(path) {
    window.history.pushState({}, '', path)
    setPath(path)
  }

  // 封装路由数据给Provider使用
  const routerData = {
    path
    goPath,
  }

  return (
    <RouterContext.Provider value={routerData}>
      {props.children}
    </RouterContext.Provider>
  )
}

// Route 组件
export function Route(props) {
  return (
    <RouterContext.Consumer>
      {({path, setPath}) => {
        if (props.path === path) {
          return props.component
        }
        return null
      }}
    </RouterContext.Consumer>
  )
}

export {
 BrowserRouter,
 Route,
 RouterContext 
}