(重磅来袭)react-router-dom 简明教程

1,736 阅读8分钟

由于文字太长,所以截取了部分文字,感兴趣可以关注我的公众号《人生代码》

原文在此

(重磅来袭)react-router-dom 简明教程

react-router-dom 简明教程

我们需要创建 react-pro 项目

create-react-app react-pro

cd react-pro

yarn add react-router-dom

我们看到的目录如下:

在 src 下新建一个 HelloRouter.js,代码如下:

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

// 将路由拆分成数组的形式,有点像 vue 路由配置
const routes = [
    {
        to'/',
        content'Home'
    },
    {
        to'/about',
        content'About'
    },
    {
        to'/users',
        content'Users'
    }
]

// 创建组件的一种形式,变量的形式
const lis = routes.map((item, index) => {
    return (
        <li key={index}>
            <Link to={item.to}>
                {item.content}
            </Link>
        </li>
    )
})

// 类组件的形式
class Home extends PureComponent {
    render() {
        return <h2>Home</h2>;
    }
}

class About extends PureComponent {
    render() {
        return <h2>About</h2>;
    }
}

class Users extends PureComponent {
    render() {
        return <h2>Users</h2>;
    }
}


// 这里的 Switch Route 有点类似 js 中的 switch case 表示精准匹配
export default class HelloRouter extends PureComponent {
    render() {
        return (
            <Router>
                <div>
                    <nav>
                        <ul>
                            {lis}
                        </ul>
                    </nav>

                    {/* A <Switch> looks through its children <Route>s and
                renders the first one that matches the current URL. */}
                    <Switch>
                        <Route path="/about" component={About} />
                        <Route path="/users" component={Users} />
                        <Route path="/" component={Home} />
                    </Switch>
                </div>
            </Router>
        );
    }
}

效果如下:

嵌套路由

接下来我们就来写写 react 的嵌套路由;

首先我们在 src 下新建一个 QianTaoRouter.js,具体代码如下:

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

const routes = [
    {
        to: '/',
        content: 'Home'
    },
    {
        to: '/about',
        content: 'About'
    },
    {
        to: '/users',
        content: 'Users'
    },
    {
        to: '/topics',
        content: 'Topics'
    }
]

const lis = routes.map((item, index) => {
    return (
        <li key={index}>
            <Link to={item.to}>
                {item.content}
            </Link>
        </li>
    )
})


class Home extends PureComponent {
    render() {
        return <h2>Home</h2>;
    }
}

class About extends PureComponent {
    render() {
        return <h2>About</h2>;
    }
}

class Users extends PureComponent {
    render() {
        return <h2>Users</h2>;
    }
}

function Topic() {
    let { topicId } = useParams();
    return <h3>Requested topic ID: {topicId}</h3>;
}

function Topics() {
    let match = useRouteMatch();
    console.log("matach", match)
    return (
        <div>
          <h2>Topics</h2>
    
          <ul>
            <li>
              <Link to={`${match.url}/components`}>Components</Link>
            </li>
            <li>
              <Link to={`${match.url}/props-v-state`}>
                Props v. State
              </Link>
            </li>
          </ul>
    
          {/* The Topics page has its own <Switch> with more routes
              that build on the /topics URL path. You can think of the
              2nd <Route> here as an "index" page for all topics, or
              the page that is shown when no topic is selected */}
          <Switch>
            <Route path={`${match.path}/:topicId`}>
              <Topic />
            </Route>
            <Route path={match.path}>
              <h3>Please select a topic.</h3>
            </Route>
          </Switch>
        </div>
      );
}



export default class HelloRouter extends PureComponent {
    render() {
        return (
            <Router>
                <div>
                    <nav>
                        <ul>
                            {lis}
                        </ul>
                    </nav>

                    {/* A <Switch> looks through its children <Route>s and
                renders the first one that matches the current URL. */}
                    <Switch>
                        <Route path="/about" component={About} />
                        <Route path="/users" component={Users} />
                        <Route path="/topics" component={Topics} />
                        <Route path="/" component={Home} />
                    </Switch>
                </div>
            </Router>
        );
    }
}

其中引人注意的是

  • useRouteMatch 用于解析路由对象
  • useParams 用于解析路由参数

主要组件

路由组件: BrowserRouter和HashRouter

BrowserRouter使用浏览器的History API来管理url及与浏览器进行交互, 需要服务器增加配置以让所有的url请求返回同一个页面

HashRouter将页面当前位置存储在url的hash部分(http://example.com/#/your/page.),不需要服务器增加特殊配置

路由匹配组件Route和Switch

Switch组件搜索其下路由Route组件,渲染第一个匹配到的路由而忽略其他 Route为视图渲染出口

<Switch>
  <Route path={`${match.path}/:topicId`}>
    <Topic />
  </Route>
  <Route path={match.path}>
    <h3>Please select a topic.</h3>
  </Route>
</Switch>

导航组件Link,NavLink和Redirect

Link组件用来在应用中创建链接。Link会被渲染成a标签

<ul>
  <li>
    <Link to={`${match.url}/components`}>Components</Link>
  </li>
  <li>
    <Link to={`${match.url}/props-v-state`}>
      Props v. State
    </Link>
  </li>
</ul>

NavLink是一种特殊类型的Link,支持自动添加active class

<NavLink to="/react" activeClassName="hurray">
  React
</NavLink>

// When the URL is /react, this renders:
// <a href="/react" className="hurray">React</a>

// When it's something else:
// <a href="/react">React</a>

任何时候你想强制导航,你可以渲染一个Redirect组件。当渲染时,它将使用其来支持导航

<Redirect to="/login" />

代码分割

即code-splitting, 网页的增量下载, 未使用到的包不会加载 我们使用webpack, @babel/plugin-syntax-dynamic-import, 和 loadable-components来实现代码分割 首先安装依赖包

yarn add @babel/preset-react @babel/plugin-syntax-dynamic-import loadable-components --dev

配置.babelrc文件(没有的话在项目根目录下新建一个)

{
  "presets": ["@babel/preset-react"],
  "plugins": ["@babel/plugin-syntax-dynamic-import"]
}

修改App.js

import React from "react";
import { BrowserRouter as RouterRouteSwitch } from "react-router-dom";
import loadable from "@loadable/component";
import Loading from "../components/Loading";
import "./App.css";

const Counter = loadable(() => import("../features/counter/Counter"), {
  fallback<Loading />,
});
const Book = loadable(() => import("../features/book/Book"), {
  fallback<Loading />,
});

function App() {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Counter} />
        <Route path="/book" component={Book} />
      </Switch>
    </Router>
  );
}

export default App;

滚动状态恢复

当路由切换时候页面自动滚动到顶部或者恢复滚动位置