zoukankan      html  css  js  c++  java
  • react-router-dom 5.X

    安装

    npm install --save react-router-dom

    使用

    导入

    import { BrowserRouter as Router, Route, Link } from "react-router-dom";
    上述import是es6语法,其中as是取别名用的

    简单实例

    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'
    
    function App() {
      return (
        <Router>
          <Route exact path="/" component={Home} />{/* exact准确匹配 */}
          <Route path="/news" component={News} />
          <Route path="/music" component={Music} />
        </Router>
      );
    }
    
    export default App;

    注意,每个路由必须被外层的Router包裹
    exact的存在是严格匹配,去掉的话,访问/news实际会渲染Home

    Link的使用

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

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

    react-router-dom 官方示例解读

    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 exact path="/">
                <Home />
              </Route>
              <Route path="/old-match">
                <Redirect to="/will-match" />
              </Route>
              <Route path="/will-match">
                <WillMatch />
              </Route>
            <Route path="*" >
                <NoMatch />
              </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

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

    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"))

     

  • 相关阅读:
    Windows 科研软件推荐
    有关Python 包 (package) 的基本知识
    《Using Python to Access Web Data》Week4 Programs that Surf the Web 课堂笔记
    Coursera助学金申请模板
    《Using Databases with Python》 Week2 Basic Structured Query Language 课堂笔记
    Jupyter 解决单个变量输出问题
    解决 pandas 中打印 DataFrame 行列显示不全的问题
    《Using Python to Access Web Data》 Week3 Networks and Sockets 课堂笔记
    缓存击穿及解决方案
    jvm垃圾收集器
  • 原文地址:https://www.cnblogs.com/tianyamoon/p/12271712.html
Copyright © 2011-2022 走看看