如何使用ReactRouterv4设置条件和响应式路由

来自菜鸟教程
跳转至:导航、​搜索

介绍

React 中的响应式路由涉及根据用户设备的视口为用户提供不同的路由。 CSS 媒体查询通常用于实现此目的,但这会限制您使用 CSS 道具显示或不显示不同的元素。 使用响应式路由,您现在可以直接根据屏幕尺寸为不同用户提供 React 应用程序的完整独立视图。

在本教程中,我们将向您展示如何在您的 React 应用程序中实现路由和提供响应式路由。 按照本教程,您将构建一个用户仪表板应用程序,该应用程序根据用户设备屏幕的大小为用户提供不同的路线。

先决条件

要完成本教程,您需要:

  • Node.js 安装在本地,您可以按照【X57X】如何安装Node.js 并创建本地开发环境【X126X】进行。

本教程已使用 Node v14.2.0、npm v6.14.5、react v16.3.2、react-router-dom v5.2.0 和 react-media v1.10.0 进行了验证.

第 1 步 — 设置项目

要启动您的项目,请使用 npxcreate-react-app 创建一个新的 React 应用程序:

npx create-react-app responsive-routing

然后,导航到新的项目目录:

cd responsive-routing

接下来,安装成功构建此演示所需的必要模块。 这些模块是 react-router-domreact-media。 您可以通过运行以下命令来安装它们:

npm install react-router-dom@5.2.0 react-media@1.10.0

现在,您可以通过运行以下命令来启动应用程序:

npm start

注意: 虽然不需要路由,但本教程使用 Bulma CSS 框架进行样式和布局。

您可以使用以下终端命令添加 Bulma:

npm install bulma@0.6.2

并将以下内容添加到您的 index.js 中:

index.js

import 'bulma/css/bulma.css';

在这一步中,您已经设置了项目并添加了 Bulma 框架用于样式和布局。

第 2 步 - 添加 React 路由器

要将路由添加到您的项目,您需要修改 index.js 文件以在元素层次结构的根部呈现路由器:

nano index.js

首先,从 react-router-dom 导入 BrowserRouter 并将其别名为 Router

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from "react-router-dom";
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

然后,将 <React> 替换为 <Router>

index.js

ReactDOM.render(
  <Router>
    <App />
  </Router>,
  document.getElementById('root')
);

您的应用程序现在已设置为使用 React Router。

第 3 步 — 创建 Nav 组件

页面中心的 GitHub 徽标将用作应用程序的导航部分。

在您的 src 目录中,创建一个名为 Nav 的新目录:

mkdir src/Nav

您将需要添加 GitHub 徽标并将其保存为 logo.svg 在此目录中。

接下来,在这个目录下创建一个index.js文件:

nano src/Nav/index.js

并添加以下代码:

src/Nav/index.js

import React from 'react';
import './Nav.css';
import logo from './logo.svg';

const Nav = () => (
  <nav>
    <img src={logo} alt="Logo" />
  </nav>
);

export default Nav;

接下来,在这个目录下创建一个Nav.css文件:

nano src/Nav/Nav.css

导航组件具有以下样式:

src/Nav/Nav.css

nav {
  display: flex;
  justify-content: center;
  height: 50px;
  margin-bottom: 10px;
}

nav > img {
  display: block;
  width: 50px;
  height: auto;
}

现在,让我们通过修改 App.js 文件来渲染 Nav 组件。

nano src/App.js

导入 Nav 组件并在您的 App 组件中使用它:

src/App.js

import React, { Component } from 'react';
import Nav from './Nav';

class App extends Component {
  render() {
    return (
      <div>
        <Nav />
      </div>
    );
  }
}

export default App;

现在,当您在 Web 浏览器中打开您的应用程序时,您应该会看到您添加的徽标。

第 4 步 — 创建 UsersCard 组件

用户卡将负责显示用户的详细信息。 它将包含 avatarnameusername 等信息。 它还将显示 followersfollowingrepos

在您的应用程序的 src 目录中,创建一个新的 Users 目录:

mkdir src/Users

接下来,在这个目录下创建一个UsersCard.js文件:

nano src/Users/UsersCard.js

并添加以下代码:

src/Users/UsersCard.js

import React from 'react';
import { Link } from 'react-router-dom';
import './UsersCard.css'

const UsersCard = ({ user, match }) => <Link to={`${match.url}/${user.id}`} className="column card">
  <img src={user.avatar} alt=""/>
  <p className="users-card__name">{user.name}</p>
  <p className="users-card__username">@{user.username}</p>
  <div className="users-card__divider"></div>
  <div className="users-card__stats">
    <div>
      <p>{user.followers}</p>
      <span>Followers</span>
    </div>
    <div>
      <p>{user.following}</p>
      <span>Following</span>
    </div>
    <div>
      <p>{user.repos}</p>
      <span>Repositories</span>
    </div>
  </div>
</Link>;

export default UsersCard;

react-router-dom 中的 Link 组件用于允许用户在单击卡片时导航以查看单个用户的详细信息。

例如,如果 UsersCardid10009,则 Link 组件将生成如下 URL:

localhost:3000/10009
  • localhost:3000 表示当前 URL。
  • 10009 表示 $user.id

所有这些信息都将在渲染组件时传递。

接下来,在这个目录下创建一个UsersCard.css文件:

nano src/users/UsersCard.css

UsersCard 组件具有以下样式:

src/Users/UsersCard.css

.card {
  border-radius: 2px;
  background-color: #ffffff;
  box-shadow: 0 1.5px 3px 0 rgba(0, 0, 0, 0.05);
  max-width: 228px;
  margin: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0;
}

.card img {
  width: 50px;
  height: auto;
  border-radius: 50%;
  display: block;
  padding: 15px 0;
}

.users-card__name {
  font-weight: 400;
  font-size: 16.5px;
  line-height: 1.19;
  letter-spacing: normal;
  text-align: left;
  color: #25292e;
}

.users-card__username {
  font-size: 14px;
  color: #707070;
}

.users-card__divider {
  border: solid 0.5px #efefef;
  width: 100%;
  margin: 15px 0;
}

.users-card__stats {
  display: flex;
}

.users-card__stats p {
  font-size: 20px;
}

.users-card__stats div {
  margin: 10px;
  text-align: center;
}

.users-card__stats span {
  color: #707070;
  font-size: 12px;
}

此时您有一个 UsersCard 组件。 接下来,您需要在列表中显示这些卡片。

第 5 步 — 创建 UsersList 组件

要让您的应用程序列出用户,您需要首先创建一个 UsersList 组件。

src/Users目录下创建一个UsersCard.js文件:

nano UsersList.js

让我们编辑UsersList.js如下。

首先,您将进行必要的导入:

src/Users/UsersList.js

import React from 'react';
import UsersCard from './UsersCard';
import './UsersList.css';

定义一个 listOfUsersPerRow 函数,该函数将构建一个 UsersCard 与它们在 users 数组中的位置一致:

// ...

const listOfUsersPerRow = (users, row, itemsPerRow, match) =>
  users
    .slice((row - 1) * itemsPerRow, row * itemsPerRow)
    .map(user => <UsersCard user={user} key={user.id} match={match} />);

定义一个 listOfRows 函数,该函数将构建包含 UsersCard"columns",由 itemsPerRow 的数量定义:

// ...

const listOfRows = (users, itemsPerRow, match) => {
  const numberOfUsers = users.length;
  const rows = Math.ceil(numberOfUsers / itemsPerRow);

  return Array(rows)
    .fill()
    .map((val, rowIndex) => (
    <div className="columns">
        {listOfUsersPerRow(users, rowIndex + 1, itemsPerRow, match)}
    </div>
  ));
};

listOfUsersPerRowlistOfRows 函数可确保您在每行中的卡片数量不超过指定数量。

然后,使用函数创建一个 UsersList

src/Users/UsersList.js

//...

const UsersList = ({ users, itemsPerRow = 2, match }) => (
  <div className="cards">
    <h3 className="is-size-3 has-text-centered">Users</h3>
    {listOfRows(users, itemsPerRow, match)}
  </div>
);

export default UsersList;

接下来,在这个目录下创建一个UsersList.css文件:

nano src/Users/UsersList.css

UsersList 组件具有以下样式:

src/Users/UsersList.css

.cards {
  margin-left: 20px;
}

.columns {
  margin-top: 0;
}

此时,您有一个由 UsersCard 组成的 UsersList 组件。 接下来,您将需要单个用户的详细视图。

第 6 步 — 创建 UsersDetails 组件

当从UsersList中单击单个UsersCard时,将在详细信息部分下显示单个UsersCard

src/Users目录下创建一个UsersDetails.js文件:

nano UsersDetails.js

并添加以下代码:

src/Users/UsersDetails.js

import React from 'react';
import UsersCard from './UsersCard';

const UsersDetails = ({ user, match }) => <div>
  <h3 className="is-size-3 has-text-centered">Details</h3>
    <UsersCard user={user} match={match} />
  </div>;

export default UsersDetails;

此时,您有一个 UsersDetails 组件。 接下来,您将显示 UsersListsUsersDetails

第 7 步 — 创建 UsersDashboard 组件

要制作仪表板组件,您将显示 UsersList,当单击 UsersCard 时,在屏幕一侧显示 UsersDetails 而无需重新加载页面。

src/Users目录下创建一个UsersDashboard.js文件:

nano src/Users/UsersDashboard.js

并添加以下代码:

src/Users/UsersDashboard.js

import React from 'react';
import { Route } from 'react-router-dom';
import UsersList from './UsersList';
import UsersDetails from './UsersDetails';

const UsersDashboard = ({ users, user, match }) => (
  <div className="columns">
    <div className="column">
      <UsersList users={users} match={match} />
    </div>
    <div className="column">
      <Route
        path={match.url + '/:id'}
        render={props => (
          <UsersDetails
            user={
              users.filter(
                user => user.id === parseInt(props.match.params.id, 10)
              )[0]
            }
            match={match}
          />
        )}
      />
    </div>
  </div>
);

export default UsersDashboard;

在此代码段中,您使用了 react-router-dom 提供的 Route 组件作为组件,用于在点击卡片时显示特定的用户详细信息。

至此,您已经拥有了应用程序的所有组件。

第 8 步 — 将它们放在一起

现在,让我们把这一切放在一起。

重新访问 App.js 文件:

nano src/App.js

添加 RedirectUsersDashboard

src/App.js

import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import Nav from './Nav';
import UsersDashboard from './Users/UsersDashboard';
import './App.css';

添加包含 users 数组的 state

src/App.js

//...

class App extends Component {
  state = {
    users: [
      {
        id: 39191,
        avatar: 'https://avatars0.githubusercontent.com/u/39191?v=4',
        name: 'Paul Irish',
        username: 'paulirish',
        followers: '12k',
        following: '1k',
        repos: '1.5k'
      },
      // ... other user data
    ]
  };

  // ...
}

// ...

RouteUsersDashboard 添加到 App 组件:

class App extends Component {
  // ...

  render() {
    return (
      <div className="App">
        <Nav />
        <Route
          path="/dashboard"
          render={props => (
            <UsersDashboard users={this.state.users} {...props} />
          )}
        />
        <Redirect from="/" to="/dashboard"/>
        <Redirect from="/users" to="/dashboard"/>
      </div>
    );
  }
}

// ...

现在,在 Web 浏览器中查看您的应用程序时,您应该会看到 UsersList。 单击 UsersCard 时,您将看到它显示在 UsersDetails 中。

第 9 步 — 设置响应式路由

当用户访问此应用程序时,无论屏幕大小如何,他们都会获得相同的视图和功能。 在成熟的应用程序中,为用户提供他们可以正常享受的体验是很好的。 一种方法是为他们提供与其确切设备尺寸相匹配的视图。 您现在将在您的应用程序中实现它。

大屏访问应用时,跳转到应用的/dashboard路径,小屏查看时,跳转到应用的/users路径应用。

src/App.js 文件更新为如下所示:

src/App.js

import React, { Component } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom'; // add Switch
import Media from 'react-media'; // add Media
import Nav from './Nav';
import UsersList from './Users/UsersList'; // add UsersList
import UsersDetails from './Users/UsersDetails'; // add UsersDetails
import UsersDashboard from './Users/UsersDashboard';
import './App.css';

class App extends Component {
  // ...

  render() {
    return (
      <div className="App">
        <Nav />
        <Media query="(max-width: 599px)">
          {matches =>
            matches ? (
              <Switch>
                <Route
                  exact
                  path="/users"
                  render={props => (
                    <UsersList users={this.state.users} {...props} />
                  )}
                />
                <Route
                  path="/users/:id"
                  render={props => (
                    <UsersDetails
                      user={
                        this.state.users.filter(
                          user =>
                            user.id === parseInt(props.match.params.id, 10)
                        )[0]
                      }
                      {...props}
                    />
                  )}
                />
                <Redirect from="/" to="/users"/>
                <Redirect from="/dashboard" to="/users"/>
              </Switch>
            ) : (
              <Switch>
                <Route
                  path="/dashboard"
                  render={props => (
                    <UsersDashboard users={this.state.users} {...props} />
                  )}
                />
                <Redirect from="/" to="/dashboard"/>
                <Redirect from="/users" to="/dashboard"/>
              </Switch>
            )
          }
        </Media>
      </div>
    );
  }
}

export default App;

在此代码段中,您使用了 Media 组件来检查屏幕的大小。 如果屏幕宽度小于 599px,您可以为不同的路由设置想要显示的内容,并将 //dashboard 路由重定向到 [X169X ] 路线。

如果屏幕尺寸大于 599px,您将显示在上一步中建立的完整用户仪表板。

运行应用程序:

npm start

与您的应用程序交互并调整您的屏幕大小,以查看在与应用程序交互时如何以不同方式处理路由。

根据屏幕尺寸提供不同的路由提供了媒体查询之外的东西,因为您现在可以根据用户的设备尺寸为用户提供专门设计的组件。

结论

在本文中,您了解了使用 React 的基于组件的路由以及如何在您的 React 应用程序中实现条件渲染。

有关本教程的完整代码示例,请查看 GitHub 上的 responsive-routing 存储库。

如果您想了解有关 React 的更多信息,请查看我们的 如何在 React.js 中编码,或查看 我们的 React 主题页面 以了解练习和编程项目。