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

     

  • 相关阅读:
    Django通过中间件配置解决跨域
    Kindeditor初始化、及初始化编辑内容
    Bootstrap免费后台管理模版
    微信小程序开发-网络请求-GET/POST不同方式等
    微信小程序开发-文件系统
    微信小程序开发学习记录-源码分享
    【转载】python实例手册
    【改良的选择排序 】
    【选择 插入 冒泡排序】
    【python基础】 Tkinter 之 几何管理器
  • 原文地址:https://www.cnblogs.com/tianyamoon/p/12271712.html
Copyright © 2011-2022 走看看