如何使用 React Router v4 设置条件路由和响应路由

介绍

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

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

演示显示卡片调整到页面大小

先决条件

要完成本教程,您需要:

本教程已通过 Node v14.2.0、npmv6.14.5、reactv16.3.2、react-router-domv5.2.0 和react-mediav1.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

索引.js
import 'bulma/css/bulma.css';

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

第 2 步 – 添加 React 路由器

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

  • nano index.js

首先,导入BrowserRouterfromreact-router-dom并将其别名为Router

索引.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>

索引.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/导航/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;
}

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

  • nano src/App.js

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

源代码/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/用户/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;

Link从组件react-router-dom被用来允许用户导航被点击卡时查看单个用户的详细信息。

例如,如果 aUsersCard有一个idof 10009Link组件将生成一个像这样的 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组件。

UsersCard.jssrc/Users目录中创建一个文件

  • nano UsersList.js

让我们编辑UsersList.js如下。

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

源代码/用户/用户列表.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函数,函数将构建"columns"包含UsersCard由 数量定义的 s 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

源代码/用户/用户列表.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/用户/用户列表.css
.cards {
  margin-left: 20px;
}

.columns {
  margin-top: 0;
}

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

第 6 步 – 创建UsersDetails组件

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

UsersDetails.jssrc/Users目录中创建一个文件

  • 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单击a 时UsersDetails,在屏幕一侧显示 ,而无需重新加载页面。

UsersDashboard.jssrc/Users目录中创建一个文件

  • nano src/Users/UsersDashboard.js

并添加以下代码:

源代码/用户/用户仪表板.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;

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

此时,您已拥有应用程序的所有组件。

第 8 步 – 将它们放在一起

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

重温App.js文件:

  • nano src/App.js

添加RedirectUsersDashboard

源代码/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';

添加state包含以下内容的数组users

源代码/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文件更新为如下所示:

源代码/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路线重定向/users路线。

如果屏幕大小大于599px,则显示上一步中建立的完整用户仪表板。

运行应用程序:

npm start

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

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

结论

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

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

如果您想了解有关 React 的更多信息,请查看我们的How To Code in React.js系列,或查看我们的 React 主题页面以获取练习和编程项目。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁