ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

分步实现 react-router

2021-03-08 09:30:12  阅读:241  来源: 互联网

标签:react 分步 props 组件 router history children Router location


安装 react-router-dom

yarn add react-router-dom

新建页面,可以随便创建,将创建的页面导入、并添加路由在 App.js ,如下:

import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'
<Router>
   <Link to='/'>首页</Link> |
   <Link to='/react-redux'>react-redux</Link> |
   <Link to='/redux'>redux</Link> |
   <Link to='/hook'>Hook</Link>
   <Switch>
      <Route exact path="/" component={HomePage} />
      <Route path="/react-redux" component={ReactReduxPage} />
      <Route path="/redux" component={ReduxPage} />
      <Route path="/hook" component={HooksPage} />
      {/* <Route  component={404} /> */}
   </Switch>
</Router>

明确 react-router-dom Api 的作用

   BrowserRouter : Router的一种,通过使用HTML5提供的history API(pushState,replaceState,propstate)机制来维持页面UI同RUL的统一。
   HashRouter : 使⽤用URL的hash部分(即window.location.hash)来保持UI同RUL的统一。
   MemoryRouter : 把URL的历史记录保存在内存中的 <Router>(不读取、不写⼊地址栏)。在测试和⾮浏览器器环境中很有⽤用,如React Native。
   Router : 路由器,作为中间件传递数据。
   Link : a 链接,跳转页面。
   Switch : 匹配路由(独占路由)。
   Route : 路由,渲染页面(children、component、render)。
   Redirect : 重定向到的URL。
   Prompt : 跳出当前路由时,提示。

实现,BrowserRouter.js

其实BrowserRouter作为区分项目中路由的选择性 API,其作用肯定就是向下传递路径,也就是对象 history。然后子组件监听,并选择其与之相对应的匹配方式。

    1. 组件Router作为子组件,并下传递属性和 children。
    1. 利用history这个库的 api 来获取当前路径。
import React from 'react'
import Router from './Router';
import { createBrowserHistory } from 'history';
export default class BrowserRouter extends React.Component {
    constructor(props) {
        super(props);
        this.history = createBrowserHistory()
    }
    componentDidMount() { }
    render() {
        return <Router history={this.history} children={this.props.children} />
    }
}

实现,Router.js

    1. 作为路由器,也就是一个最上级的路由控制件。其作用就是初始化路由,并监听路由,然后将数据传递下去,触发更新。
    1. 因为要触发更新,且需要向子组件传递数据,而子组件为多层级(Link、Switch、Route 等),则需要使用 APIcontext
import React from 'react';
const RouterContext = React.createContext()
export default RouterContext
    1. 创建后,组件Router便可以使用,并向子组件传递属性。
<RouterContext.Provider
    value={{
       history: this.props.history,
       location: this.state.location,
       match: Router.computeRootMatch(this.state.location.pathname),
    }
    }
>
    { this.props.children}
</RouterContext.Provider >
    1. 处理监听,并复制
  props.history.listen((location) => {
      this.setState({
            location
      })
   })
    1. 初始化路径(每次打开页面需要初始化路径,才能显示)。
static computeRootMatch(pathname) {
     return { path: "/", url: "/", params: {}, isExact: pathname === "/" };
  }

实现Link.js

    1. 根据路径可知,该组件起的作用定时那
    1. 所以实现 跳转,并去除刷新,即可完成此组件。
const handleClick = (event) => {
   event.preventDefault();
   context.history.push(to)
}
...
<a href={to} onClick={handleClick} {...restProps}>{children}</a>

实现Route.js

    1. 该组件最主要的作用就是渲染页面,但是源码中给了三个属性:children、component、render。这三个属性均可实现组件(页面)的渲染。
<Route exact path="/" children={ChildFn}  />
<Route exact path="/"  component={HomePage} />
<Route exact path="/" render={() => <div>Home</div>} />
    1. 路由配置并匹配检测渲染、传递属性及store
const { location } = context
const { path, children, component, render, computedMatch } = this.props
const match = computedMatch
   ? computedMatch : path
         ? matchPath(location.pathname, this.props) : context.match;
    1. 无论写 children、component、render 中的哪一个,都会渲染,那么为什么会有三个呢?源码是这样的:
<RouterContext.Provider value={props}>
   {props.match
      ? children
      ? typeof children === "function"
         ? __DEV__
            ? evalChildrenDev(children, props, this.props.path)
            : children(props)
         : children
      : component
      ? React.createElement(component, props)
      : render
      ? render(props)
      : null
      : typeof children === "function"
      ? __DEV__
      ? evalChildrenDev(children, props, this.props.path)
      : children(props)
      : null}
</RouterContext.Provider>

可见,匹配的顺序是children>component>render

实现Switch.js

    1. 作用是匹配(独占)路由,白话说就是:遇见第一个一样的,我就渲染与路径,无论是 或 。
    1. 反之,没有则匹配 404.
<Route path="/about" component={About} />
<Route path="/:user" component={User} />
<Route component={404} />

如果URL是/about时,<Switch> 将开始寻找匹配的<Route> 。此时找到第一个 将会被正确匹配,并渲染,然后,后面的便不再渲染,这就是独占。其原理就是:利用React原生APIReact.Children.forEach递归,并定位当前的child

React.Children.forEach(this.props.children, (child) => {
   if (match == null) {
         element = child;
         match = child.props.path ? matchPath(location.pathname, child.props) : context.match
   }
});

最后,就是整理思路。

    1. 明确API的作用和数据的流向。
    1. 利用可复用的组件和路径的匹配进行匹配并渲染。

本文源码归处☞源码

标签:react,分步,props,组件,router,history,children,Router,location
来源: https://blog.csdn.net/xunyicao_e/article/details/114519837

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有