ReactRouter知识点

React
470
0
0
2022-11-10

本文讨论的React Router版本是V5以上的

react-router和react-router-dom的区别

img

为什么有时候我们看到如下的写法:

写法1:

import {Switch, Route, Router, browserHistory, Link} from 'react-router-dom';

写法2:

import {Switch, Route, Router} from 'react-router';
import {BrowserRouter as Router, Link} from 'react-router-dom';

先简单说下各自的功能:

  • react-router: 实现了路由的核心功能
  • react-router-dom(用于浏览器环境): 基于react-router,加入了在浏览器运行环境下的一些功能,例如:Link组件,会渲染一个a标签,Link组件源码a标签行; BrowserRouter和HashRouter 组件,前者使用pushState和popState事件构建路由,后者使用window.location.hash和hashchange事件构建路由。
  • react-router-native: 基于react-router,类似react-router-dom,加入了react-native运行环境下的一些功能。

react-router-dom依赖react-router,所以我们使用npm安装依赖的时候,只需要安装相应环境下的库即可,不用再显式安装react-router。基于浏览器环境的开发,只需要安装react-router-dom

如上所说,我们使用react开发web应用,所以只需要安装react-router-dom。

  npm install react-router-dom --save

Router

所有路由器组件的通用低级接口。通常情况下,应用程序会使用其中一个高级别路由器来代替

  • <BrowserRouter>
  • <HashRouter>
  • <MemoryRouter>
  • <NativeRouter>
  • <StaticRouter>

比如📢<Router history="{browserHistory}"></Router>< BrowserRouter></BrowserRouter >表达的是一样的意思

The most common use-case for using the low-levelis to synchronize a custom history with a state management lib like Redux or Mobx. Note that this is not required to use state management libs alongside React Router, it’s only for deep integration.

三种路由模式

本文档中的 "history "和 "history对象 "是指history,包,它是React Router仅有的两个主要依赖项之一(除了React本身),它提供了几种不同的实现,用于在各种环境中管理JavaScript的会话历史。

React Router 是建立在 history 之上的。简而言之,一个 history 知道如何去监听浏览器地址栏的变化, 并解析这个 URL 转化为 location 对象, 然后 router 使用它匹配到路由,最后正确地渲染对应的组件。

常用的 history 有三种形式, 但是你也可以使用 React Router 实现自定义的 history。

  • browserHistory
  • hashHistory
  • createMemoryHistory
Memory history 不会在地址栏被操作或读取。这就解释了我们是如何实现服务器渲染的。同时它也非常适合测试和其他的渲染环境(像 React Native )。

用法

import React from "react";
import {
  Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
import {createMemoryHistory} from 'history'

// This site has 3 pages, all of which are rendered
// dynamically in the browser (not server rendered).
//
// Although the page does not ever refresh, notice how
// React Router keeps the URL up to date as you navigate
// through the site. This preserves the browser history,
// making sure things like the back button and bookmarks
// work properly.

export default function BasicExample() {
  return (
    <Router history={createMemoryHistory()}>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/dashboard">Dashboard</Link>
          </li>
        </ul>

        <hr />

        {/*
          A <Switch> looks through all its children <Route>
          elements and renders the first one whose path
          matches the current URL. Use a <Switch> any time
          you have multiple routes, but you want only one
          of them to render at a time
        */}
        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/dashboard">
            <Dashboard />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

可点击demo体验,记得复制粘贴部分代码

确实不会引起地址栏的变化

MemoryRouter与StaticRouter的区别

  • MemoryRouter :Athat keeps the history of your “URL” in memory (does not read or write to the address bar). Useful in tests and non-browser environments like React Native.
  • Athat never changes location.This can be useful in server-side rendering scenarios when the user isn’t actually clicking around, so the location never actually changes. Hence, the name: static. It’s also useful in simple tests when you just need to plug in a location and make assertions on the render outpu

MemoryRouter主要是用于非浏览器环境,它的历史记录是放在内存中的并不会改变地址栏

StaticRouter主要用于服务端渲染, StaticRouter是无状态的,与BrowserRouter的区别就是这样 BrowserRouter:A <Router> that uses the· HTML5 history API (pushState, replaceState and the popstate event) to keep your UI in sync with the URL.

这里我理解的无状态就是o keep your UI in sync with the URL. StaticRouter不需要保持UI同步(以浏览器来说,我们的url变化,UI对应更新,但可能是局部的,会保留部分状态),由于服务端是无状态的,我只要拿到对应的组件渲染出HTML扔给客户端就行

这是我的理解,欢迎其他同学补充

注意:SSR服务端渲染路由是要HTML5 history ,所以这里也是不拿HashRouter比较的原因

官网是用MemoryRouter做测试用,StaticRouter是用于服务端渲染,但是我觉得MemoryRouter也可以用于服务端渲染,因为它本身可以用于非浏览器环境

Vue官方也有提到

img

img

img

// src/server.tsx
import { Routes } from "@/routes";
import { createStore, StoreCtx } from "@/store";
import * as React from "react";
import { StaticRouter } from "react-router";

function ServerRender(req, context, initStore) {
  return props => {
    // hook 要在这、函数组件内部调用 
    const value = createStore(initStore);
    return (
      <StoreCtx.Provider value={value}> 
        <StaticRouter location={req.url} context={context}> 
          <Routes /> 
        </StaticRouter> 
      </StoreCtx.Provider>
    );
  };
}

参考文献

  • https://reactrouter.com/core/guides/philosophy
  • https://zhuanlan.zhihu.com/p/101129994
  • https://github.com/remix-run/react-router/issues/7166
  • https://segmentfault.com/a/1190000022066757