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

    未完待续...

  • 相关阅读:
    选择主要的构建实践方法(转) Tech
    201671010109 201620172《java程序设计》第一周感想
    201671010109 201720162第二周学习感想
    2016710101090 20162017《java程序设计》第三周感想
    sort k 详解
    java.util.NoSuchElementException: None.get的解决方法
    Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace 解决方法
    Java学习随笔之1: Java 语言概述和开发环境
    java 学习随笔之2:理解面向对象
    Selenium Basic Knowledge
  • 原文地址:https://www.cnblogs.com/GManba/p/13290719.html
Copyright © 2020-2023  润新知