react-router-dom5.x使用示例

react-router-dom5.x使用示例

      • 安装
      • 使用
      • BasicExample--基础实例
      • UrlParams--动态路由
      • Nesting--嵌套路由
      • AuthRoute--路由鉴权
      • CustomLink--自定义路由
      • PreventingTransitions--阻止过渡
      • NO Match--404
      • Sidebar 侧边栏
      • config 路由配置
      • Query parameters 查询参数

  • 学习资源推荐

  • 微信扫码关注公众号 :前端前端大前端,追求更精致的阅读体验 ,一起来学习啊
  • 关注后发送关键资料,免费获取一整套前端系统学习资料和老男孩python系列课程
    在这里插入图片描述

安装

npm install --save react-router-dom

使用

import React from 'react';
import {
      BrowserRouter as Router, Route, Link } from "react-router-dom";
import Home from './components/Home'
import News from './components/News'
import Music from './components/Music'

//exact表示严格匹配,去掉的话,访问/news实际会渲染Home,News两个组件
function App() {
     
  return (
    <Router>
      <Route exact path="/" component={
     Home} />
      <Route path="/news" component={
     News} />
      <Route path="/music" component={
     Music} />
    </Router>
  );
}

export default App;

Link的使用

类似vue的vue-router,实际每个Link默认被渲染为a标签

 	  <Link to='/' > 首页</Link>
      <Link to='/news'>新闻</Link>
      <Link to='/music'>音乐</Link>

BasicExample–基础实例

分析

这是一个最基础的路由示例,根据不同的url渲染不同的组件。值得注意的是,对于Route组件而言,支持的渲染组件方式不唯一单标签的时候可以使用component属性,render属性,或者children属性挂载要渲染的组件。双标签的时候包裹要渲染的组件,也就是children…

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

const Home = () => <h2>Home</h2>
const About = () => <h2>About</h2>
const Dashboard = () => <h2>Dashboard</h2>
const News = () => <h2>News</h2>
const Games = () => <h2>Games</h2>

export default function () {
     
    return (
        <Router>
            <div>
                <ul>
                    <li> <Link to="/">Home</Link> </li>
                    <li>  <Link to="/about">About</Link>  </li>
                    <li>  <Link to="/dashboard">Dashboard</Link> </li>
                    <li>  <Link to="/news">News</Link> </li>
                    <li>  <Link to="/games">Games</Link> </li>
                </ul>
                <hr />
                <Switch>
                    <Route exact path="/"> <Home /></Route>
                    <Route path="/about" component={
     About} />
                    <Route path="/dashboard" children={
     <Dashboard />} />
                    <Route path="/news" render={
     ()=><News />} />
                    <Route path="/games" component={
     ()=><Games/>} />
                </Switch>
            </div>
        </Router>
    );
}

UrlParams–动态路由

分析

该示例演示了动态路由是如何匹配的,以及如何获取匹配到的参数值。和很多框架匹配规则一致,都是:param.在获取参数的时候,可以用hooks形式 ,也可以用原始的props.match.params.xxx

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


export default function () {
     
    return (
        <Router>
            <div>
                <h2>Accounts</h2>
                <ul>
                    <li>
                        <Link to="/netflix/1">Netflix</Link>
                    </li>
                    <li>
                        <Link to="/zillow-group/2">Zillow Group</Link>
                    </li>
                    <li>
                        <Link to="/yahoo/3">Yahoo</Link>
                    </li>
                    <li>
                        <Link to="/modus-create/4">Modus Create</Link>
                    </li>
                </ul>
                <Switch>
                    <Route path="/:page/:num" component={
     Child} />
                </Switch>
            </div>
        </Router>
    );
}

function Child(props) {
     
    let {
      page} = useParams();
    let num=props.match.params.num;
    return (
        <div>
            <h3>
                当前页: {
     page}--数字:{
     num}
            </h3>
        </div>
    );
}

Nesting–嵌套路由

分析

嵌套路由适用于有明显层级划分的情况,以官方示例来看,主层级分为home和topics,topics又划分出三个子主题,这就涉及到了嵌套路由。子路由的url都是在父级路由基础上拼接出来的。像这样 /topics /topics/rendering。值得注意的是,这个案例里用到了一个新的hooks,useRouteMatch,这就相当于原始的props.match.此外,这个示例里对useRouteMatch()解构了path和url,如果你打印一下,你会发现它们的值是一样的,也许就像原文解释那样,一个用来获取父路径,一个用于Link组件的跳转,更规范?

import React from "react";
import {
     
    BrowserRouter as Router,
    Switch,
    Route,
    Link,
    useParams,
    useRouteMatch
} from "react-router-dom";

const Home = () => <h2>Home</h2>

const Topic = () => {
     
    let {
      topicId } = useParams();
    return <h3>{
     topicId}</h3>
}


const Topics = () => {
     

    let {
      path, url } = useRouteMatch();
    return (
        <div>
            <h2>Topics</h2>
            <ul>
                <li><Link to={
     `${
       url}/rendering`}>Rendering with React</Link></li>
                <li><Link to={
     `${
       url}/components`}>Components</Link></li>
                <li><Link to={
     `${
       url}/props-v-state`}>Props v. State</Link></li>
            </ul>
            <Switch>
                <Route exact path={
     path}> <h3>Please select a topic.</h3></Route>
                <Route path={
     `${
       path}/:topicId`} component={
     Topic} />
            </Switch>
        </div>
    );
}



export default function () {
     
    return (
        <Router>
            <div>
                <ul>
                    <li><Link to="/">Home</Link></li>
                    <li><Link to="/topics">Topics</Link></li>
                </ul>
                <hr />
                <Switch>
                    <Route exact path="/" component={
     Home} />
                    <Route path="/topics" component={
     Topics} />
                </Switch>
            </div>
        </Router>
    );
}

在这里插入图片描述

AuthRoute–路由鉴权

分析

这是一个简化后的改写demo.核心是通过高阶组件+状态控制实现路由鉴权。在实际开发中,有些页面必须登录才可以访问,甚至不同身份的人看到的页面也是不一样的。public页面都可以访问,protected页面必须登录才可以访问。登录状态这里使用一个变量isLogin控制.Redirect 组件用于身份验证不通过时重定向处理,useHistory 钩子函数可获取历史记录接口,控制页面跳转。PrivateRoute 是一个高阶组件,对基础的Route进行了进一步封装,注意...rest,在这里相当于将高阶组件获取的path属性传递给Route

import React from "react";
import {
     
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  Redirect,
  useHistory,
} from "react-router-dom";

let isLogin = false;

const LoginBtn = () =>   <button onClick={
     ()=>{
     isLogin = true}}>登录</button>


const LoginOutBtn = () => {
     
  let history=useHistory();
  return <button onClick={
     ()=>{
     isLogin = false;history.push("/login")}}>退出登录</button>
}

const Login = () => <LoginBtn/>

const Condition = ({
      children }) => isLogin ? children : <Redirect to="/login" />

const PrivateRoute = ({
      children, ...rest }) => {
     
  return (
    <Route   {
     ...rest} render={
     () => <Condition children={
     children} />} />
  );
}


export default function () {
     
  return (
    <Router>

      <p><Link to={
     "/public"} >public</Link></p>
      <p><Link to={
     "/protected"}>protected</Link></p>
      <Switch>
        <Route exact path="/" render={
     () => <h3>home</h3>} />
        <Route path="/public" render={
     () => <h3>public</h3>} />
        <Route path="/login" component={
     Login} />
        <PrivateRoute path="/protected">
          <h2>已经登录 可查看-protected</h2>
          <LoginOutBtn/>
        </PrivateRoute>
      </Switch>
    </Router>
  )

}


CustomLink–自定义路由

分析

自定义路由本质是在Route组件的基础上加入了一些定制化处理,相当于包裹了一层。为了更好理解,这里对官方示例做了个微调,强匹配属性exact直接写入而不是传参形式体现。useRouteMatch可以根据path返回一个匹配结果对象,exact表示强匹配
,借助于Route组件,useRouteMatch可以空调用,像这样useRouteMatch().反之,需要传参。可参考上一篇中的嵌套路由,对比查看。

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


const Home = () => <h2>Home</h2>
const About = () => <h2>About</h2>

export default function () {
     
    return (
        <Router>
            <div>
                <MyLink to="/" label="Home" />
                <MyLink to="/about" label="About" />
                <hr />
                <Switch>
                    <Route exact path="/" component={
     Home} />
                    <Route path="/about" component={
     About} />
                </Switch>
            </div>
        </Router>
    );
}

function MyLink({
      label, to }) {
     


    let match = useRouteMatch({
     
        path: to,
        exact: true
    })
    // 这里返回的match对象仅用于样式控制

    return (
        <div className={
     match ? "active" : ""}>
            {
     match && "> "}
            <Link to={
     to}>{
     label}</Link>
        </div>
    );
}




PreventingTransitions–阻止过渡

分析

正常情况下,在用户在表单中填写了一些信息但是没提交的情况下,点击其他页面跳转链接,等再返回的时候,表单数据会丢失。这个例子就是提供一种阻断方式,在进行页面跳转的时候给用户一个提示,确认后会跳转,避免因为误操作导致的表单数据丢失。提示这里使用的是Prompt组件,when属性为一个布尔值,true弹出提示框,message为具体的提示信息。Prompt也可以写在form之外,保证在要渲染的组件里即可。这种场景,通常用于长表单输入,比如注册。关于Prompt,还有个好用的点,下边单独介绍。

import React, {
      useState } from "react";
import {
     
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  Prompt
} from "react-router-dom";

// Sometimes you want to prevent the user from
// navigating away from a page. The most common
// use case is when they have entered some data
// into a form but haven't submitted it yet, and
// you don't want them to lose it.

export default function PreventingTransitionsExample() {
     
  return (
    <Router>
      <ul>
        <li>
          <Link to="/">Form</Link>
        </li>
        <li>
          <Link to="/one">One</Link>
        </li>
        <li>
          <Link to="/two">Two</Link>
        </li>
      </ul>

      <Switch>
        <Route path="/" exact children={
     <BlockingForm />} />
        <Route path="/one" children={
     <h3>One</h3>} />
        <Route path="/two" children={
     <h3>Two</h3>} />
      </Switch>
    </Router>
  );
}

function BlockingForm() {
     
  let [isBlocking, setIsBlocking] = useState(false);

  return (
    <form
      onSubmit={
     event => {
     
        event.preventDefault();
        event.target.reset();
        setIsBlocking(false);
      }}
    >
      <Prompt
        when={
     isBlocking}
        message={
     location =>
          `Are you sure you want to go to ${
       location.pathname}`
        }
      />

      <p>
        Blocking?{
     " "}
        {
     isBlocking ? "Yes, click a link or the back button" : "Nope"}
      </p>

      <p>
        <input
          size="50"
          placeholder="type something to block transitions"
          onChange={
     event => {
     
            setIsBlocking(event.target.value.length > 0);
          }}
        />
      </p>

      <p>
        <button>Submit to stop blocking</button>
      </p>
    </form>
  );
}

Prompt

  • message属性还可以接收一个函数,该函数可以获取到下一个位置(location),返回true不提示,反之,弹出提示
      <Prompt
        message={
     location =>
          location.pathname.startsWith("/one")
            ? true
            : `Are you sure you want to go to ${
       location.pathname}?`
        }
      />

NO Match–404

分析

该示例演示的是对404的处理,用于捕获所有未匹配的项,通常放置于Switch的最后一项Route里,匹配规则为*。当然,也许你还想将所有的未捕获页面都跳转到/error,这个需要使用重定向,后边会介绍

import React from "react";
import {
     
  BrowserRouter as Router,
  Route,
  Link,
  Switch,
  Redirect,
  useLocation
} from "react-router-dom";



export default function NoMatchExample() {
     
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/old-match">Old Match, to be redirected</Link>
          </li>
          <li>
            <Link to="/will-match">Will Match</Link>
          </li>
          <li>
            <Link to="/will-not-match">Will Not Match</Link>
          </li>
          <li>
            <Link to="/also/will/not/match">Also Will Not Match</Link>
          </li>
        </ul>

        <Switch>
        <Route path="*" >
            <NoMatch />
          </Route>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/old-match">
            <Redirect to="/will-match" />
          </Route>
          <Route path="/will-match">
            <WillMatch />
          </Route>
         
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
     
  return <h3>Home</h3>;
}

function WillMatch() {
     
  return <h3>Matched!</h3>;
}

function NoMatch() {
     
  let location = useLocation();

  return (
    <div>
      <h3>
        No match for <code>{
     location.pathname}</code>
      </h3>
    </div>
  );
}

统一处理404

代码看起来像这样,如此一来,所有的404都会统一跳转到/error

 <Switch>
  <Route path="/one" component={
     One}/>
  <Route path="/two" component={
     Two}/>
  <Route path="/error" component={
     Error}/>
  <Redirect from="/*" to="/error" />
</Switch>

Sidebar 侧边栏

分析

侧边栏这个案例很常见,官方示例里边介绍的除了基础侧边栏,还扩展了一种多处渲染的方式。即当路由匹配到当前url时,可以在应用给程序内任何你想渲染的地方去分别渲染sideber和main,注意下边的map遍历,只有children属性那里有差异

import React from "react";

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


const routes = [
  {
     
    path: "/",
    exact: true,
    sidebar: () => <div>home!</div>,
    main: () => <h2>Home</h2>
  },
  {
     
    path: "/bubblegum",
    sidebar: () => <div>bubblegum!</div>,
    main: () => <h2>Bubblegum</h2>
  },
  {
     
    path: "/shoelaces",
    sidebar: () => <div>shoelaces!</div>,
    main: () => <h2>Shoelaces</h2>
  }
];

export default function SidebarExample() {
     
  return (
    <Router>
      <div style={
     {
      display: "flex" }}>
        <div
          style={
     {
     
            padding: "10px",
            width: "40%",
            background: "#f0f0f0"
          }}
        >
          <ul style={
     {
      listStyleType: "none", padding: 0 }}>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/bubblegum">Bubblegum</Link>
            </li>
            <li>
              <Link to="/shoelaces">Shoelaces</Link>
            </li>
          </ul>

          <Switch>
            {
     routes.map((route, index) => (
             
              <Route
                key={
     index}
                path={
     route.path}
                exact={
     route.exact}
                
                children={
     <route.sidebar />}
              />
            ))}
          </Switch>
        </div>

        <div style={
     {
      flex: 1, padding: "10px" }}>
          <Switch>
            {
     routes.map((route, index) => (
              <Route
                key={
     index}
                path={
     route.path}
                exact={
     route.exact}
                
                children={
     <route.main />}
              />
            ))}
          </Switch>
        </div>
      </div>
    </Router>
  );
}



render(<SidebarExample/>,document.getElementById("root"))

效果图
react-router-dom5.x使用示例_第1张图片

  • 结合效果图来看,侧边栏底部和右侧,都进行了渲染,即多处渲染。注意,这两次其实除了渲染的组件不同,其他都一样

config 路由配置

分析

有时候,也许你希望将路由集中配置,比如放在一个数组里,每个路由对象包含path和component。涉及嵌套的,就再来一个数组,存放子路由对象。

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


const Sandwiches = () => <h2>Sandwiches</h2>
const Bus = () => <h2>Bus</h2>
const Cart = () => <h2>Cart</h2>

const routes = [
  {
     
    path: "/sandwiches",
    component: Sandwiches
  },
  {
     
    path: "/tacos",
    component: Tacos,
    routes: [
      {
     
        path: "/tacos/bus",
        component: Bus
      },
      {
     
        path: "/tacos/cart",
        component: Cart
      }
    ]
  }
];

export default function App() {
     
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/tacos">Tacos</Link>
          </li>
          <li>
            <Link to="/sandwiches">Sandwiches</Link>
          </li>
        </ul>


        <Switch>
          {
     routes.map((route, i) => (
            <RouteWithSubRoutes key={
     i} {
     ...route} />
          ))}
        </Switch>
      </div>
    </Router>
  );
}


function RouteWithSubRoutes(route) {
     

  return (
    <Route
      path={
     route.path}
      render={
     (props) => {
     
        return <route.component {
     ...props} routes={
     route.routes} />
      }}
    />
  );
}




function Tacos({
      routes }) {
     
  return (
    <div>
      <h2>Tacos</h2>
      <ul>
        <li>
          <Link to="/tacos/bus">Bus</Link>
        </li>
        <li>
          <Link to="/tacos/cart">Cart</Link>
        </li>
      </ul>

      <Switch>
        {
     routes.map((route, i) => (
          <RouteWithSubRoutes key={
     i} {
     ...route} />
        ))}
      </Switch>
    </div>
  );
}




render(<App />, document.getElementById("root"))

Query parameters 查询参数

分析

该示例其实本质是借用了浏览器内置的URLSearchParams,这个方法可以很方便的解析url参数,但这个存在兼容问题,放弃IE家族就没问题了。具体URLSearchParamsAPI,可参考MDN这段示例代码:

var paramsString = "q=URLUtils.searchParams&topic=api"
var searchParams = new URLSearchParams(paramsString);

searchParams.has("topic") === true; // true
searchParams.get("topic") === "api"; // true
searchParams.getAll("topic"); // ["api"]
searchParams.get("foo") === null; // true
searchParams.append("topic", "webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
searchParams.set("topic", "More webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev"
searchParams.delete("topic");
searchParams.toString(); // "q=URLUtils.searchParams"
import React from "react";
import {
      render } from 'react-dom'
import {
     
  BrowserRouter as Router,
  Link,
  useLocation
} from "react-router-dom";



export default function App() {
     
  return (
    <Router>
      <QueryParamsDemo />
    </Router>
  );
}

//这里是重点
function useQuery() {
     
  return new URLSearchParams(useLocation().search);
}

function QueryParamsDemo() {
     
  let query = useQuery();
  return (
    <div>
      <div>
        <h2>Accounts</h2>
        <ul>
          <li>
            <Link to="/account?name=netflix">Netflix</Link>
          </li>
          <li>
            <Link to="/account?name=zillow-group">Zillow Group</Link>
          </li>
          <li>
            <Link to="/account?name=yahoo">Yahoo</Link>
          </li>
          <li>
            <Link to="/account?name=modus-create">Modus Create</Link>
          </li>
        </ul>

        <Child name={
     query.get("name")} />
      </div>
    </div>
  );
}

function Child({
      name }) {
     
  return (
    <div>
      {
     name ? (
        <h3>
          The <code>name</code> in the query string is &quot;{
     name}
          &quot;
        </h3>
      ) : (
        <h3>There is no name in the query string</h3>
      )}
    </div>
  );
}




render(<App />, document.getElementById("root"))

你可能感兴趣的:(react)