Pull to refresh

React Hook Router современная альтернатива React Router

Reading time8 min
Views35K
image

Вольный перевод публикации How React Hooks can replace React Router.
Автор Peter Ekene Eze.

С момента появления React Hooks многое изменилось. Возможности, предоставляемые хуками, позволили пересмотреть наш подход к определенным концепциям в React, в том числе и к маршрутизации.

Этот пост никоим образом не предназначен для того, чтобы списывать со счетов React Router или приуменьшать его важность. Мы изучим другие возможности и посмотрим, как мы можем улучшить работу с маршрутизацией в приложениях React, используя хуки.

С этой целью мы сравним React Router и hooksrouter на наглядных примерах. Для начала давайте поближе посмотрим на React Router.

React Router


React Router — это популярный декларативный способ управления маршрутами в приложениях React. Он уменьшает объем работ, связанных с ручной настройкой маршрутов для всех страниц и экранов в приложении. React Router предоставляет нам три основных компонента, которые помогают нам сделать маршрутизацию — Route, Link и BrowserRouter.

Маршрутизация в React Router


Представим, что мы создаем React приложение, состоящее из трех страниц. Обычно для маршрутизации мы используем React Router и пишем примерно такой код:

import Users from "./components/Users";
import Contact from "./components/Contact";
import About from "./components/About";
function App() {
  return (
    <div>
      <Router>
        <div>
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
          <Route path="/contact" component={Contact} />
        </div>
      </Router>
    </div>
  );
}

Компонент <Route />, импортированный из пакета React Router, принимает два параметра: путь, по которому переходит пользователь, и компонент для отображения по указанному пути.

Хуки как альтернативная маршрутизация


Модуль hookrouter экспортирует хук useRoutes(), который проверяет предопределенный объект маршрутов и возвращает результат. В объекте маршрутов вы определяете свои маршруты как ключи, а их значения — как функции, которые будут вызываться при совпадении маршрутов. Пример кода на хуках:

import Users from "./components/Users";
import Contact from "./components/Contact";
import About from "./components/About";

const Routes = {
  "/": () => ,
  "/about": () => ,
  "/contact": () => 
};
export default Routes;

Такой вариант написания маршрутов более привлекательный. Почему? Потому что нам не потребовалось выполнять много работы. С React Router нам пришлось отрисовать компонент <Route /> для всех отдельных маршрутов в нашем приложении. Не говоря уже обо всех параметрах, которые мы передали ему. С помощью хуков, мы можем использовать наши маршруты, просто передав их в хук useRoutes():

import {useRoutes} from 'hookrouter';
import Routes from './router'

function App() {
  const routeResult = useRoutes(Routes)
  return routeResult
}

Это дает нам точно такой же результат, который мы получили бы, используя React Router, но с более чистой и легкой реализацией.

React Router навигация


React Router включает в себя компонент <Link/>, который помогает нам настраивать навигацию по приложению и управлять интерактивной маршрутизацией. У нас есть приложение с тремя страницами, давайте отобразим их на экране и перейдем к ним при нажатии:

import { Route, Link, BrowserRouter as Router } from "react-router-dom";
import Users from "./components/Users";
import Contact from "./components/Contact";
import About from "./components/About";

function App() {
  return (
    <div className="App">
      <Router>
        <div>
          <ul>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
          <Route path="/contact" component={Contact} />
        </div>
      </Router>
    </div>
  );
}

Мы создали навигацию, которая нужна для перехода с одной страницы приложения на другую. Вот наглядный пример того, как это работает.



Используем хуки для навигации


Модуль hookrouter предоставляет обертку <A/> над HTML-тегом <a/>. Он доступен как react компонент и на 100% совместим с нативным тегом <a/>. Единственное отличие состоит в том, что он перемещает навигацию в стек истории вместо фактической загрузки новой страницы.

const routes = {
  "/user": () => <Users />,
  "/about": () => <About />,
  "/contact": () => <Contact />
};

function App() {
  const routeResult = useRoutes(routes);
  return (
    <div className="App">
      <A href="/user">Users Page</A>
      <A href="/about">About Page</A>
      <A href="/contact">Contacts Page</A>
      {routeResult}
    </div>
  );
}



Программная навигация


Модуль hookrouter дает нам доступ к хуку navigate(), в который мы можем передать URL, и он будет перенаправлять пользователя по этому URL. Каждый вызов функции navigate() представляет собой навигацию вперед, в результате пользователи могут нажать кнопку «Назад» в браузере, чтобы вернуться к предыдущему URL-адресу. Это происходит по умолчанию.

navigate('/user/');

Однако, если вам нужно другое поведение, вы можете сделать замену в истории браузера. Хук navigate() принимает три параметра — navigate(url, [replace], [queryParams]), второй параметр используется для изменения поведения замены. Он удаляет текущую запись истории и заменяет ее новой. Чтобы достичь этого эффекта, просто установите его аргумент в значение true.

navigate('/user', true);

React Router switch


React Router использует компонент <Switch /> для отображения страницы по умолчанию, когда определенные маршруты не совпадают. Обычно он отображает страницу 404, чтобы сообщить пользователю, что выбранный маршрут не определен в приложении. Для этого мы оборачиваем все маршруты внутри компонента <Switch /> и отрисовываем страницу 404, не определяя для нее путь к файлу:

import { Route, Link, BrowserRouter as Router, Switch } from "react-router-dom";
import Users from "./components/Users";
import Contact from "./components/Contact";
import Home from "./components/About";
import NoPageFound from "./components/NoPageFound.js";

function App() {
  return (
    <div className="App">
      <Router>
        <div>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>
          <Switch>
            <Route exact path="/" component={Home} />
            <Route path="/users" component={Users} />
            <Route path="/contact" component={Contact} />
            <Route component={NoPageFound} />
          </Switch>
        </div>
      </Router>
    </div>
  );
}

Таким образом, при переходе на неопределенный маршрут React Router отображает компонент NoPageFound. Таким способом мы можем информировать пользователей о том, где они находятся и что происходит во время навигации по приложению.

Альтернатива switch на хуках


Поскольку мы определяем объект маршрутов, который содержит все наши маршруты, и просто передаем этот объект в хук useRoutes(), становится очень просто отображать маршруты по условию. Если мы определим компонент NoPageFound для рендеринга по умолчанию, когда выбранный маршрут не определен, нам нужно будет только передать этот файл для рендеринга вместе с нашей функцией результата следующим образом:

import { useRoutes, A } from "hookrouter";
import routes from "./router";
import NoPageFound from "./components/NoPageFound";
function App() {
  const routeResult = useRoutes(routes);
  return (
    <div className="App">
      <A href="/user">Users Page</A> <br />
      <A href="/about">About Page</A>
      <br />
      <A href="/contact">Contacts Page</A> <br />
      {routeResult || <NoPageFound />}
    </div>
  );
}



По сравнению с использованием компонента в React Router для рендеринга страниц по умолчанию это выглядит немного чище и более читабельно.

React Router редиректы


Редирект происходит, когда мы хотим динамически направить пользователя с одного маршрута на другой. Например, во время авторизации, когда пользователь успешно входит в систему, мы бы хотели перенаправить его с маршрута '/ login' на маршрут '/ dashboard'.

С React Router мы можем сделать это несколькими способами — используя объект истории или компонент <Redirect />. Например, если у нас есть форма входа в систему, мы можем использовать объект истории браузера, чтобы перенаправить пользователя к маршруту '/ dashboard' при входе в систему:

import React from 'react'
class Login extends React.Component {
  loginUser = () => {
  // if (user is logged in successfully)
    this.props.history.push('/dashboard')
  }
  render() {
    return (
      <form>
        <input type="name" />
        <input type="email" />
        <button onClick={this.loginUser}>Login</button>
      </form>
    )
  }
}
export default Login

Редиректы с помощью хуков


Модуль hookrouter предоставляет нам хук useRedirect(), который может принимать исходный маршрут и целевой маршрут в качестве параметров.

useRedirect('/user', '/dashboard');

Это автоматически перенаправит пользователей на маршрут '/dashboard', когда будет найден путь '/user'. Например, если мы не хотим показывать каких-либо пользователей, а вместо этого автоматически перенаправляем пользователя на его /dashboard, мы напишем это так:

import {useRoutes, useRedirect} from 'hookrouter';
import dashboard from "./components/Dashboard";
const routes = {
    '/home': () => <Users />,
    '/dashboard': () => <Dashboard />
};
const Users = () => {
    useRedirect('/user', '/dashboard');
    const routeResult = useRoutes(routes);
    return routeResult
}



Стоит отметить, что хук useRedirect() вызывает замену истории навигации. В результате в истории навигации будет только одна запись. Это означает, что если перенаправление происходит с '/user' на '/dashboard, как было в последнем, рассматриваемом фрагменте кода, маршрут '/user' не будет отображаться в истории просмотра. У нас будет только маршрут '/ dashboard'.

Обработка параметров URL в React Router


Параметры URL помогают нам отображать компоненты на основе их динамических URL. Это работает аналогично с вложенными маршрутами, однако в этом случае маршруты не меняются, а обновляются.

Например, если бы в нашем приложении были разные пользователи, имело бы смысл идентифицировать их отдельно с их индивидуальными маршрутами, такими как 'user/user1/' и 'users/user2/' и т.д. Для этого нам нужно использовать параметры URL. В React Router мы просто передаем параметр (например, id), начинающийся с двоеточия, в свойстве path у компонента <Route />:

<Route path="users/:id" component={Users} />

Используем хуки для обработки параметров URL


Практически нет отличий в обработке параметров URL в hookrouter и React Router. Конструкция та же (т.е. вы можете передать параметры URL-адреса целевым маршрутам, используя двоеточие и имя параметра).

Тем не менее, есть разница в том, как работает hookrouter. Он читает все параметры URL и помещает их в объект. Это делается с помощью ключей, которые вы определили в объекте маршрутов. Затем все названные параметры будут перенаправлены в функцию результата вашего маршрута как объединенный объект.

const routes = {
  '/user/:id': ({id}) => <User userId={id} />
}

Используя деструктуризацию объекта, мы просто берем свойство id из объекта props и затем применяем его к нашему компоненту. Таким образом, мы получаем точно такой же результат, как и с React Router.

Заключение


Мы рассмотрели альтернативный способ маршрутизации в React приложениях. React Router — отличный инструмент, однако, с появлением хуков в React многое изменилось, в том числе и то, как работает маршрутизация. Этот модуль на основе хуков предлагает более гибкий и чистый способ обработки маршрутов в небольших проектах.

Помимо основного функционала, рассмотренного в посте, hookrouter имеет ряд дополнительных возможностей, таких как:

  • Lazy loading компонентов
  • Вложенные маршруты
  • Передача дополнительных данных в маршрут
  • Перехват навигации
  • Поддержка серверного рендеринга

У проекта hookrouter отличная документация, в которой очень быстро можно найти интересующий вопрос.

В статье были использованы материалы из документации к hookrouter
и оригинальной статьи How React Hooks can replace React Router.

Git-репозиторий hookrouter

UPD: при оформлении статьи не увидел сразу, что можно выбрать тип публикации «Перевод», прошу прощения у читателей, оформил в шапке ссылку на оригинал и указал автора.
Tags:
Hubs:
Total votes 15: ↑12 and ↓3+9
Comments27

Articles