zoukankan      html  css  js  c++  java
  • react-router-dom 学习笔记

    react-router-dom

    react-router-dom 是 React 的实现路由功能的组件。

    依赖安装

    npm install react-router-dom --save
    

    功能演示

    路由和跳转

    codesandbox 地址:https://codesandbox.io/s/react-router-basic-bnpsd?from-embed

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link
    } from "react-router-dom";
    
    // 下面一共有3个页面, 所有页面都是又浏览器动态的渲染, 而不是服务端渲染
    // 尽管页面没有刷新, 但是 React Router 会保证路由URL和你点击的目标地址保持一致
    // 它维护了浏览器的历史状态, 保证了书签或者返回按钮能够正常使用
    
    // 下面的例子用到了 react-router-dom 组件的3个标签
    // 1. Switch 保证只渲染一个子路由组件
    // 2. Route 用于配置路由
    // 3. Link 用于路由跳转
    
    export default function BasicExample() {
      return (
        <Router>
          <div>
            <ul>
              <li>
                <Link to="/">Home</Link>
              </li>
              <li>
                <Link to="/about">About</Link>
              </li>
              <li>
                <Link to="/dashboard">Dashboard</Link>
              </li>
            </ul>
    
            <hr />
    
            {/*这里使用了 Switch, 是为了保证当多个路由都匹配成功时, 只渲染第一个匹配到的路由组件*/}
            <Switch>
              <Route exact path="/">
                <Home />
              </Route>
              <Route path="/about">
                <About />
              </Route>
              <Route path="/dashboard">
                <Dashboard />
              </Route>
            </Switch>
          </div>
        </Router>
      );
    }
    
    function Home() {
      return (
        <div>
          <h2>Home</h2>
        </div>
      );
    }
    
    function About() {
      return (
        <div>
          <h2>About</h2>
        </div>
      );
    }
    
    function Dashboard() {
      return (
        <div>
          <h2>Dashboard</h2>
        </div>
      );
    }
    
    

    路由参数

    codesandbox 地址:https://codesandbox.io/s/react-router-url-parameters-rrbsb?from-embed=&file=/example.js

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      useParams
    } from "react-router-dom";
    
    export default function ParamsExample() {
      return (
        <Router>
          <div>
            <h2>Accounts</h2>
            <ul>
              <li>
                <Link to="/netflix">Netflix</Link>
              </li>
              <li>
                <Link to="/zillow-group">Zillow Group</Link>
              </li>
              <li>
                <Link to="/yahoo">Yahoo</Link>
              </li>
              <li>
                <Link to="/modus-create">Modus Create</Link>
              </li>
            </ul>
    
            <Switch>
              <Route path="/:id" children={<Child />} />
            </Switch>
          </div>
        </Router>
      );
    }
    
    function Child() {
      // 这里使用了 react hooks
      let { id } = useParams();
      return (
        <div>
          <h3>ID: {id}</h3>
        </div>
      );
    }
    
    

    查询参数

    import React from "react";
    import {
      BrowserRouter as Router,
      Link,
      useLocation
    } from "react-router-dom";
    
    // React Router does not have any opinions about
    // how you should parse URL query strings.
    //
    // If you use simple key=value query strings and
    // you do not need to support IE 11, you can use
    // the browser's built-in URLSearchParams API.
    //
    // If your query strings contain array or object
    // syntax, you'll probably need to bring your own
    // query parsing function.
    
    export default function QueryParamsExample() {
      return (
        <Router>
          <QueryParamsDemo />
        </Router>
      );
    }
    
    // A custom hook that builds on useLocation to parse
    // the query string for you.
    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>
      );
    }
    

    嵌套路由

    体验地址:https://reactrouter.com/web/example/nesting

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      useParams,
      useRouteMatch
    } from "react-router-dom";
    
    export default function NestingExample() {
      return (
        <Router>
          <div>
            <ul>
              <li>
                <Link to="/">Home</Link>
              </li>
              <li>
                <Link to="/topics">Topics</Link>
              </li>
            </ul>
            <hr />
            <Switch>
              <Route exact path="/">
                <Home />
              </Route>
              <Route path="/topics">
                <Topics />
              </Route>
            </Switch>
          </div>
        </Router>
      );
    }
    
    function Home() {
      return (
        <div>
          <h2>Home</h2>
        </div>
      );
    }
    
    function Topics() {
      /**
       * 在 NestingExample 中我们是这样使用 Topics 组件的:
       * <Route path="/topics">
       *   <Topics />
       * </Route>
       * 使用 useRouteMatch 时就能找到 Route 组件  <Route path="/topics"></Route>
       */
      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`}>
              <Topic />
            </Route>
          </Switch>
        </div>
      );
    }
    
    function Topic() {
      let { topicId } = useParams();
      return (
        <div>
          <h3>{topicId}</h3>
        </div>
      );
    }
    
    

    路由重定向

    codesandbox(这个官方例子有一个BUG): https://reactrouter.com/web/example/auth-workflow,路由重定向在实现权限管理是很有用的。

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      Redirect,
      useHistory,
      useLocation
    } from "react-router-dom";
    
    // 1. 这个例子有3个页面:公开页面, 受保护页面(登录后才能访问), 登录页面
    // 2. 如果未登录访问受保护页面, 会重定向到登录页面, 登录之后重定向到受保护页面
    
    // Notice the URL change each time. If you click the back
    // button at this point, would you expect to go back to the
    // login page? No! You're already logged in. Try it out,
    // and you'll see you go back to the page you visited
    // just *before* logging in, the public page.
    
    export default function AuthExample() {
      return (
        <Router>
          <div>
            <AuthButton />
    
            <ul>
              <li>
                <Link to="/public">Public Page</Link>
              </li>
              <li>
                <Link to="/protected">Protected Page</Link>
              </li>
            </ul>
    
            <Switch>
              <Route path="/public">
                <PublicPage />
              </Route>
              <Route path="/login">
                <LoginPage />
              </Route>
              <PrivateRoute path="/protected">
                <ProtectedPage />
              </PrivateRoute>
            </Switch>
          </div>
        </Router>
      );
    }
    
    const fakeAuth = {
      isAuthenticated: false,
      authenticate(cb) {
        fakeAuth.isAuthenticated = true;
        setTimeout(cb, 100); // fake async
      },
      signout(cb) {
        fakeAuth.isAuthenticated = false;
        setTimeout(cb, 100);
      }
    };
    
    function AuthButton() {
      let history = useHistory();
      console.log(fakeAuth)
      return fakeAuth.isAuthenticated ? (
        <p>
          Welcome!{" "}
          <button
            onClick={() => {
              fakeAuth.signout(() => history.push("/"));
            }}
          >
            Sign out
          </button>
        </p>
      ) : (
        <p>You are not logged in.</p>
      );
    }
    
    // A wrapper for <Route> that redirects to the login
    // screen if you're not yet authenticated.
    function PrivateRoute({ children, ...rest }) {
      return (
        <Route
          {...rest}
          render={({ location }) =>
            fakeAuth.isAuthenticated ? (
              children
            ) : (
              <Redirect
                to={{
                  pathname: "/login",
                  state: { from: location }
                }}
              />
            )
          }
        />
      );
    }
    
    function PublicPage() {
      return <h3>Public</h3>;
    }
    
    function ProtectedPage() {
      return <h3>Protected</h3>;
    }
    
    function LoginPage() {
      let history = useHistory();
      let location = useLocation();
    
      let { from } = location.state || { from: { pathname: "/" } };
      let login = () => {
        fakeAuth.authenticate(() => {
          history.replace(from);
        });
      };
    
      return (
        <div>
          <p>You must log in to view the page at {from.pathname}</p>
          <button onClick={login}>Log in</button>
        </div>
      );
    }
    
    

    codesandbox: https://reactrouter.com/web/example/custom-link,思路是使用高阶组件来实现。

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      useRouteMatch
    } from "react-router-dom";
    
    // This example show how you could create a custom
    // <Link> that renders something special when the URL
    // is the same as the one the <Link> points to.
    
    export default function CustomLinkExample() {
      return (
        <Router>
          <div>
            <OldSchoolMenuLink
              activeOnlyWhenExact={true}
              to="/"
              label="Home"
            />
            <OldSchoolMenuLink to="/about" label="About" />
    
            <hr />
    
            <Switch>
              <Route exact path="/">
                <Home />
              </Route>
              <Route path="/about">
                <About />
              </Route>
            </Switch>
          </div>
        </Router>
      );
    }
    
    function OldSchoolMenuLink({ label, to, activeOnlyWhenExact }) {
      let match = useRouteMatch({
        path: to,
        exact: activeOnlyWhenExact
      });
    
      return (
        <div className={match ? "active" : ""}>
          {match && "> "}
          <Link to={to}>{label}</Link>
        </div>
      );
    }
    
    function Home() {
      return (
        <div>
          <h2>Home</h2>
        </div>
      );
    }
    
    function About() {
      return (
        <div>
          <h2>About</h2>
        </div>
      );
    }
    
    

    阻止页面跳转

    codesandbox: https://reactrouter.com/web/example/preventing-transitions,这个功能非常常见,如果你使用过 vue-router,那么你应该熟悉它关于导航守卫的一些方法。在 react-router-dom 中,主要依靠 Prompt 来实现这个功能,默认是一个非常丑的 prompt 弹窗,当然您可以配置(通过BrowserRouter或HashRouter配置属性getUserConfirmation)

    import React, { useState } from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      Prompt
    } from "react-router-dom";
    
    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>
      );
    }
    
    

    404 页面配置

    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>
      );
    }
    

    递归路由

    codesandbox: https://reactrouter.com/web/example/recursive-paths,这个例子非常有趣,玩一玩才能体会

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      Redirect,
      useParams,
      useRouteMatch
    } from "react-router-dom";
    
    // Sometimes you don't know all the possible routes
    // for your application up front; for example, when
    // building a file-system browsing UI or determining
    // URLs dynamically based on data. In these situations,
    // it helps to have a dynamic router that is able
    // to generate routes as needed at runtime.
    //
    // This example lets you drill down into a friends
    // list recursively, viewing each user's friend list
    // along the way. As you drill down, notice each segment
    // being added to the URL. You can copy/paste this link
    // to someone else and they will see the same UI.
    //
    // Then click the back button and watch the last
    // segment of the URL disappear along with the last
    // friend list.
    
    export default function RecursiveExample() {
      return (
        <Router>
          <Switch>
            <Route path="/:id">
              <Person />
            </Route>
            <Route path="/">
              <Redirect to="/0" />
            </Route>
          </Switch>
        </Router>
      );
    }
    
    function Person() {
      let { url } = useRouteMatch();
      let { id } = useParams();
      let person = find(parseInt(id));
    
      return (
        <div>
          <h3>{person.name}’s Friends</h3>
    
          <ul>
            {person.friends.map(id => (
              <li key={id}>
                <Link to={`${url}/${id}`}>{find(id).name}</Link>
              </li>
            ))}
          </ul>
    
          <Switch>
            <Route path={`${url}/:id`}>
              <Person />
            </Route>
          </Switch>
        </div>
      );
    }
    
    const PEEPS = [
      { id: 0, name: "Michelle", friends: [1, 2, 3] },
      { id: 1, name: "Sean", friends: [0, 3] },
      { id: 2, name: "Kim", friends: [0, 1, 3] },
      { id: 3, name: "David", friends: [1, 2] }
    ];
    
    function find(id) {
      return PEEPS.find(p => p.id === id);
    }
    

    导航菜单配置

    https://reactrouter.com/web/example/sidebar 这个例子的参考意义不大,实际需求中菜单往往也是通过 Route 配置计算而得。

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link
    } from "react-router-dom";
    
    // Each logical "route" has two components, one for
    // the sidebar and one for the main area. We want to
    // render both of them in different places when the
    // path matches the current URL.
    
    // We are going to use this route config in 2
    // spots: once for the sidebar and once in the main
    // content section. All routes are in the same
    // order they would appear in a <Switch>.
    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) => (
                  // You can render a <Route> in as many places
                  // as you want in your app. It will render along
                  // with any other <Route>s that also match the URL.
                  // So, a sidebar or breadcrumbs or anything else
                  // that requires you to render multiple things
                  // in multiple places at the same URL is nothing
                  // more than multiple <Route>s.
                  <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) => (
                  // Render more <Route>s with the same paths as
                  // above, but different components this time.
                  <Route
                    key={index}
                    path={route.path}
                    exact={route.exact}
                    children={<route.main />}
                  />
                ))}
              </Switch>
            </div>
          </div>
        </Router>
      );
    }
    

    路由过渡效果

    https://reactrouter.com/web/example/animated-transitions

    import "./packages/react-router-dom/examples/Animation/styles.css";
    
    import React from "react";
    import {
      TransitionGroup,
      CSSTransition
    } from "react-transition-group";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      Redirect,
      useLocation,
      useParams
    } from "react-router-dom";
    
    export default function AnimationExample() {
      return (
        <Router>
          <Switch>
            <Route exact path="/">
              <Redirect to="/hsl/10/90/50" />
            </Route>
            <Route path="*">
              <AnimationApp />
            </Route>
          </Switch>
        </Router>
      );
    }
    
    function AnimationApp() {
      let location = useLocation();
    
      return (
        <div style={styles.fill}>
          <ul style={styles.nav}>
            <NavLink to="/hsl/10/90/50">Red</NavLink>
            <NavLink to="/hsl/120/100/40">Green</NavLink>
            <NavLink to="/rgb/33/150/243">Blue</NavLink>
            <NavLink to="/rgb/240/98/146">Pink</NavLink>
          </ul>
    
          <div style={styles.content}>
            <TransitionGroup>
              {/*
                This is no different than other usage of
                <CSSTransition>, just make sure to pass
                `location` to `Switch` so it can match
                the old location as it animates out.
              */}
              <CSSTransition
                key={location.key}
                classNames="fade"
                timeout={300}
              >
                <Switch location={location}>
                  <Route path="/hsl/:h/:s/:l" children={<HSL />} />
                  <Route path="/rgb/:r/:g/:b" children={<RGB />} />
                </Switch>
              </CSSTransition>
            </TransitionGroup>
          </div>
        </div>
      );
    }
    
    function NavLink(props) {
      return (
        <li style={styles.navItem}>
          <Link {...props} style={{ color: "inherit" }} />
        </li>
      );
    }
    
    function HSL() {
      let { h, s, l } = useParams();
    
      return (
        <div
          style={{
            ...styles.fill,
            ...styles.hsl,
            background: `hsl(${h}, ${s}%, ${l}%)`
          }}
        >
          hsl({h}, {s}%, {l}%)
        </div>
      );
    }
    
    function RGB() {
      let { r, g, b } = useParams();
    
      return (
        <div
          style={{
            ...styles.fill,
            ...styles.rgb,
            background: `rgb(${r}, ${g}, ${b})`
          }}
        >
          rgb({r}, {g}, {b})
        </div>
      );
    }
    
    const styles = {};
    
    styles.fill = {
      position: "absolute",
      left: 0,
      right: 0,
      top: 0,
      bottom: 0
    };
    
    styles.content = {
      ...styles.fill,
      top: "40px",
      textAlign: "center"
    };
    
    styles.nav = {
      padding: 0,
      margin: 0,
      position: "absolute",
      top: 0,
      height: "40px",
       "100%",
      display: "flex"
    };
    
    styles.navItem = {
      textAlign: "center",
      flex: 1,
      listStyleType: "none",
      padding: "10px"
    };
    
    styles.hsl = {
      ...styles.fill,
      color: "white",
      paddingTop: "20px",
      fontSize: "30px"
    };
    
    styles.rgb = {
      ...styles.fill,
      color: "white",
      paddingTop: "20px",
      fontSize: "30px"
    };
    
    

    路由集中管理

    这个例子演示了,如何做到路由集中管理,真实的项目中,导航菜单的逻辑往往也是和一起路由集中管理的。

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link
    } from "react-router-dom";
    
    // Some folks find value in a centralized route config.
    // A route config is just data. React is great at mapping
    // data into components, and <Route> is a component.
    
    // Our route config is just an array of logical "routes"
    // with `path` and `component` props, ordered the same
    // way you'd do inside a `<Switch>`.
    const routes = [
      {
        path: "/sandwiches",
        component: Sandwiches
      },
      {
        path: "/tacos",
        component: Tacos,
        routes: [
          {
            path: "/tacos/bus",
            component: Bus
          },
          {
            path: "/tacos/cart",
            component: Cart
          }
        ]
      }
    ];
    
    export default function RouteConfigExample() {
      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>
      );
    }
    
    // A special wrapper for <Route> that knows how to
    // handle "sub"-routes by passing them in a `routes`
    // prop to the component it renders.
    function RouteWithSubRoutes(route) {
      return (
        <Route
          path={route.path}
          render={props => (
            // pass the sub-routes down to keep nesting
            <route.component {...props} routes={route.routes} />
          )}
        />
      );
    }
    
    function Sandwiches() {
      return <h2>Sandwiches</h2>;
    }
    
    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>
      );
    }
    
    function Bus() {
      return <h3>Bus</h3>;
    }
    
    function Cart() {
      return <h3>Cart</h3>;
    }
    

    API

    useParams hooks

    useParams可以帮助我们在各层组件中,轻松访问 router 的 params 参数。

    // V5.1以前
    const Detail = (props) => {
      const { match: { params } } = props
      const { id } = params
      return (
        <div>
          params id: { id }
          <DetailTips/>
        </div>
      )
    }
    
    // 需要使用高阶组件 withRouter
    const DetailTips = withRouter((props) => {
      const { match: { params } } = props
      const { id } = params
      return (
        <div>params id: { id }</div>
      )
    })
    
    function App() {
      return (
        <div className="App">
          <Router>
            <Switch>
              <Route path="/detail/:id" component={Detail}/>
            </Switch>
          </Router>
        </div>
      );
    }
    

    V5.1以后,由于 useParams 的引入,我们可以轻松获取路由参数。对于更深层的组件,也不需要借助高阶组件withRouter,帮助我们拿到路由参数。

    const Detail = () => {
      const { id } = useParams()
      return (
        <div>
          params id: { id }
          <DetailTips/>
        </div>
      )
    }
    
    // 不需要使用高阶组件 withRouter
    const DetailTips = () => {
      const { id } = useParams()
      return (
        <div>params id: { id }</div>
      )
    }
    
    function App() {
      return (
        <div className="App">
          <Router>
            <Switch>
              <Route path="/detail/:id" component={Detail}/>
            </Switch>
          </Router>
        </div>
      )
    }
    

    useLocation hooks

    useLocation 可以帮助我们在各层组件中,轻松获取 location 对象。在V5.1版本之前,我们需要使用props.location。而对于更深层的组件,还需要使用 withRouter。


    V5.1以前:

    const Detail = (props) => {
      const { location: { pathname } } = props
      return (
        <div>
          pathname: { pathname }
          <DetailTips/>
        </div>
      )
    }
    
    // 需要使用高阶组件 withRouter
    const DetailTips = withRouter((props) => {
      const { location: { pathname } } = props
      return (
        <div>pathname: { pathname }</div>
      )
    })
    
    function App() {
      return (
        <div className="App">
          <Router>
            <Switch>
              <Route path="/detail/:id" component={Detail}/>
            </Switch>
          </Router>
        </div>
      );
    }
    

    V5.1以后:

    const Detail = (props) => {
      const { pathname } = useLocation()
      return (
        <div>
          pathname: { pathname }
          <DetailTips/>
        </div>
      )
    }
    
    // 不需要使用高阶组件 withRouter
    const DetailTips = (props) => {
      const { pathname } = useLocation()
      return (
        <div>pathname: { pathname }</div>
      )
    }
    
    function App() {
      return (
        <div className="App">
          <Router>
            <Switch>
              <Route path="/detail/:id" component={Detail}/>
            </Switch>
          </Router>
        </div>
      );
    }
    

    useHistory hooks

    useHistory可以帮助我们访问history对象,进行编程式的导航。

    const Home = () => {
      return (
        <div>Home</div>
      )
    }
    
    const Detail = () => {
      const history = useHistory()
      return (
        <div>
          <button onClick={() => { history.push('/')}}>go home</button>
        </div>
      )
    }
    
    function App() {
      return (
        <div className="App">
          <Router>
            <Switch>
              <Route exact path="/" component={Home}/>
              <Route path="/detail/:id" component={Detail}/>
            </Switch>
          </Router>
        </div>
      );
    }
    

    useRouteMatch hooks

    useRouteMatch,接受一个path字符串作为参数。当参数的path与当前的路径相匹配时,useRouteMatch会返回match对象,否则返回null。


    useRouteMatch在对于一些,不是路由级别的组件。但是组件自身的显隐却和当前路径相关的组件时,非常有用。比如,你在做一个后台管理系统时,网页的Header只会在登录页显示,登录完成后不需要显示,这种场景下就可以用到useRouteMatch


    V5.0以前:

    const Home = () => {
      return (
        <div>Home</div>
      )
    }
    
    // Header组件只会在匹配`/detail/:id`时出现
    const Header = () => {
      return (
        <Route
          path="/detail/:id"
          strict
          sensitive
          render={({ match }) => {
            return match && <div>Header</div>
          }}
        />
      )
    }
    
    const Detail = () => {
      return (
        <div>Detail</div>
      )
    }
    
    function App() {
      return (
        <div className="App">
          <Router>
            <Header/>
            <Switch>
              <Route exact path="/" component={Home}/>
              <Route exact path="/detail/:id" component={Detail}/> 
            </Switch>
          </Router>
        </div>
      );
    }
    

    V5.1以后:

    const Home = () => {
      return (
        <div>Home</div>
      )
    }
    
    // Header组件只会在匹配`/detail/:id`时出现
    const Header = () => {
      const match = useRouteMatch('/detail/:id')
      return (
        match && <div>Header</div>
      )
    }
    
    const Detail = () => {
      return (
        <div>Detail</div>
      )
    }
    
    function App() {
      return (
        <div className="App">
          <Router>
            <Header/>
            <Switch>
              <Route exact path="/" component={Home}/>
              <Route exact path="/detail/:id" component={Detail}/> 
            </Switch>
          </Router>
        </div>
      );
    }
    

    BrowserRouter

    进阶

    路由配置

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link
    } from "react-router-dom";
    
    function Home() {
      return (
        <div>
          <div>Home</div>
        </div>
      )
    }
    
    function About() {
      return (
        <div>
          <div>About</div>
        </div>
      )
    }
    
    function Product() {
      return (
        <div>
          <div>Product</div>
        </div>
      )
    }
    
    function Layout(props) {
      return (
        <div>
          <div>layout</div>
          {props.children}
        </div>
      )
    }
    
    const routes = [
      {
        path: "/",
        component: Layout,
        children: [
          {
            path: "/home",
            title: '工作台',
            exact: true,
            component: Home
          },
          {
            path: "/about",
            title: '关于',
            exact: true,
            component: About
          },
          {
            path: "/product",
            title: '商品',
            component: Product,
          }
        ]
      }
    ];
    
    export default function SidebarExample() {
      return (
        <Router>
          <div style={{ display: "flex" }}>
            <div
              style={{
                padding: "10px",
                 "40%",
                background: "#f0f0f0",
                display: 'flex'
              }}
            >
              <ul style={{ listStyleType: "none", padding: 0 }}>
                {
                  routes.map(route => {
                    return (
                      <li key={route.title}>
                        <Link to={route.path}>{route.title}</Link>
                      </li>
                    )
                  })
                }
              </ul>
              <Switch>
                {routes.map((route, index) => (
                  <Route
                    key={index}
                    path={route.path}
                    exact={route.exact}
                    children={<route.component />}
                  />
                ))}
              </Switch>
            </div>
          </div>
        </Router>
      );
    }
    

    未完待续...

  • 相关阅读:
    使用CustomValidate自定义验证控件
    C#中金额的大小写转换
    Andriod出错之Unable to build: the file dx.jar was not loaded from the SDK folder!
    VC 编写的打字练习
    机房工作笔记Ping只有单向通
    web服务协同学习笔记(1)
    Dll 学习3 将MDI子窗口封装在DLL中
    机房工作学习文件共享
    Andriod出错之Failed to find an AVD compatible with target 'Android 2.2'
    Andriod出错之wrapper was not properly loaded first
  • 原文地址:https://www.cnblogs.com/GManba/p/13290719.html
Copyright © 2011-2022 走看看