Управление состоянием в React: практический пример

реагирование
управление состоянием
API контекста
Управление состоянием в React: практический пример cover image

React — это идеальная среда для создания динамических клиентских приложений для многих разработчиков. Динамичный характер этих приложений обусловлен гибкостью и расширенным списком возможностей и функций, которые возможны на стороне клиента, что позволило разработчикам создавать полноценные приложения, загружающиеся в браузере за считанные секунды, а это подвиг, которого раньше не было. возможно (или очень обременительно) во времена статического Интернета.

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

Эта проблема решалась во многих фреймворках, используя разные подходы и фокусируясь на разных наборах подзадач, поэтому важно иметь высокое понимание экосистемы выбранной фреймворка, чтобы оценить потребности каждого приложения и использовать правильный подход в соответствии с ними. метрики. В этой статье вы получите краткий обзор распространенных проблем управления состоянием и попытаетесь представить различные подходы (useState, Context API) в качестве ответа на них. Хотя в этой статье будет представлено несколько решений, она будет сосредоточена только на проблемах меньшего масштаба, а в следующих статьях мы рассмотрим более сложные темы.

Рабочий процесс аутентификации

Код, представленный в статье, можно найти здесь.

Ссылку на предварительный просмотр можно получить здесь.

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

User Login

Как показано на GIF-изображении выше, мы хотим разрешить пользователям входить в систему или регистрироваться в нашем приложении, используя учетные данные. Если были предоставлены действительные учетные данные, пользователь войдет в систему, приложение автоматически перейдет на домашнюю страницу, и пользователь сможет продолжить использование приложения.

Аналогично, если пользователь выходит из системы, ресурсы домашней страницы будут защищены при входе в систему, страница входа будет единственной страницей, доступной пользователю.

Рассматривая этот рабочий процесс с точки зрения реализации, у нас будет основной компонент с именем App, компонент приложения будет перенаправлять пользователя на одну из двух страниц: «Домой» или «Вход», текущее состояние пользователя (вошел в систему, вышел из системы) будет определять, какая страница, на которую перенаправляется пользователь, изменение текущего состояния пользователя (например, переход от входа в систему к выходу из системы) должно вызвать мгновенное перенаправление на соответствующую страницу.

State

Как показано на рисунке выше, мы хотим, чтобы компонент приложения учитывал текущее состояние и отображал только одну из двух страниц — «Домашняя страница» или «Вход» — на основе этого текущего состояния.

Если значение пользователя равно нулю, это означает, что у нас нет аутентифицированного пользователя, поэтому мы автоматически переходим на страницу входа и защищаем домашнюю страницу с помощью условного рендеринга. Если пользователь существует, мы делаем обратное.

Теперь, когда у нас есть четкое представление о том, что следует реализовать, давайте рассмотрим несколько вариантов, но сначала давайте настроим наш проект React.

Репозиторий проекта содержит пример серверного приложения, которое мы будем использовать для реализации клиентской части (мы не будем вдаваться в подробности, поскольку это не основная задача здесь, но код намеренно был простым, поэтому у вас не возникнет с ним проблем). )

Начнем с создания следующих страниц и компонентов:

  • Домашняя страница

  • Страница авторизации

  • Страница редактирования пользователя

  • Компонент навигации

  • Компонент UserDropdown

Приложению React с несколькими страницами необходима правильная навигация, для этого мы можем использовать response-router-dom для создания глобального контекста маршрутизатора браузера и регистрации различных маршрутов React.


yarn add react-router-dom

Мы знаем, что многие читатели предпочитают следовать инструкциям, поэтому вот стартовый шаблон, который поможет вам быстрее освоиться. Эта стартовая ветка использует DaisyUI для предопределенных компонентов TailwindCSS JSX. Он включает в себя все компоненты, страницы и уже настроенный маршрутизатор. Если вы планируете следовать этому руководству и самостоятельно построить весь процесс аутентификации, следуя простым шагам, начните с разветвления репозитория. После того как вы разветвите репозиторий, клонируйте его и начните с start-hereветки:


git clone git@github.com:<your-username>/fullstack-resourcify.git

Как только вы потянете ветку start-here:

  • Откройте проект в предпочитаемом вами редакторе кода.

  • Измените каталог на frontend/.

  • Установить зависимости: пряжа

  • Запустите сервер разработки: Yarn dev ·

Предварительный просмотр должен выглядеть примерно так:

Changing user name

Имя, отображаемое на панели навигации (вверху справа) — это переменная состояния, определенная в основном компоненте приложения. Одна и та же переменная передается как на панель навигации, так и на домашнюю страницу. Простая форма, использованная выше, фактически обновляет переменную состояния «name» из компонента EditPage.

Два подхода, представленные ниже, будут подробно рассмотрены в деталях реализации:

Первый подход: useState

useState()

useState — один из наиболее часто используемых хуков React. Он позволяет создавать и изменять состояние в функциональном компоненте React. Компонент useState имеет очень простую реализацию и удобен в использовании: чтобы создать новое состояние, вам нужно вызвать useState с начальным значением вашего состояния, а хук useState вернет массив, содержащий две переменные: первая — это состояние. переменная, которую вы можете использовать для ссылки на свое состояние, а вторая — функция, которую вы используете для изменения значения состояния: довольно просто.

Как насчет того, чтобы увидеть это в действии? Имя, отображаемое на панели навигации (вверху справа) — это переменная состояния, определенная в основном компоненте приложения. Одна и та же переменная передается как на панель навигации, так и на домашнюю страницу. Простая форма, использованная выше, фактически обновляет переменную состояния «name» из компонента EditPage. Суть в следующем: useState — это основной хук, который принимает начальное состояние в качестве параметра и возвращает две переменные, содержащие два значения: переменную состояния, содержащую начальное состояние, и функцию установки для той же переменной состояния.

Давайте разберем это и посмотрим, как это было реализовано в первую очередь.

  1. Создание переменной состояния «имя»:

./src/App.jsx


import { useState } from "react";

function App() {
const testValue = "CLA";
 //using the useState hook to create a state variable out of an initial value passed as an argument
 const [name, setName] = useState(testValue);
 console.log(`Rendering: &#36;{name}`);

 return (...)};

Реквизит

Реквизиты являются одним из основных строительных блоков компонента реагирования. Концептуально, если вы думаете о функциональном компоненте React как о функции Javascript, тогда реквизиты — это не более чем параметры функции, сочетание реквизитов и перехватчика useState может предложить вам надежную основу. для управления состоянием в простом приложении React.

Реквизиты React передаются как атрибуты пользовательским компонентам. Атрибуты, передаваемые как реквизиты, могут быть деструктурированы из объекта реквизита при принятии его в качестве аргумента, аналогично этому:

Передача реквизита

<Routes>
  <Route path="/" element={<Home name={name} />} /> // Passing name as a prop to
  Home Component
  <Route
    path="/user"
    element={<EditUser name={name} setName={setName} />} // passing both name and setItem function as props to EditUser component
  />
  <Route path="/login" element={<Login />} />
</Routes>

Пропсы можно принимать и использовать внутри функционального компонента аналогично обычным аргументам функции. Поскольку «имя» передается как свойство компоненту Home, мы можем отобразить его в том же компоненте. В следующем примере мы принимаем переданное свойство, используя синтаксис деструктуризации для извлечения свойства name из объекта props.

Принимаем реквизит

./src/pages/Home.jsx

... ...
export default function Home({name}) { //Destructuring the name property from the props object, another approach would be: Home(props.name)
 console.log("Rendering: Home");
 return (
   <div className="flex flex-col bg-white m-auto p-auto">
     <h1 className="flex py-5 lg:px-20 md:px-10 mx-5 font-bold text-2xl text-gray-800">
       Welcome {name}
     </h1>
... ...

Совет профессионала

Откройте консоль браузера и обратите внимание, как все компоненты, использующие свойство «name», перерисовываются при изменении состояния. При манипулировании переменной состояния React сохранит следующее состояние, снова отобразит ваш компонент с новыми значениями и обновит пользовательский интерфейс.

Components Re-rendering

Недостатки useState

Реквизит-Сверление

Детализация реквизитов — это термин, обозначающий иерархию компонентов, в которой набору компонентов требуются определенные реквизиты, предоставляемые родительским компонентом. Обычный обходной путь, который обычно использует неопытный разработчик, — передать эти реквизиты по всей цепочке компонентов, проблема с этим Подход заключается в том, что изменение любого из этих реквизитов приведет к повторному рендерингу всей цепочки компонентов, что эффективно замедляет работу всего приложения в результате этих ненужных рендерингов, а компоненты в середине цепочки не требуют этих реквизитов. служат средством передачи реквизита.

Пример:

  • Переменная состояния была определена в основном компоненте приложения с помощью ловушки useState().

  • В компонент Navbar было передано свойство имени.

— Та же опора принята в Navbar и еще раз передана в качестве опоры компоненту UserDropdown.

— UserDropdown — это последний дочерний элемент, который принимает свойство.

Prop-drilling

./src/App.jsx

... ...
function App() {
 const [name, setName] = useState(test);
 console.log("Rendering: App");

 return (
   <BrowserRouter>
     <div className="h-screen">
       <Navbar name={name} />

       <main className="px-4">
... ...

./src/компоненты/Navbar.jsx

import React from "react";
import Logo from "../assets/cla.svg";
import { BiSearchAlt } from "react-icons/bi";
import { Link } from "react-router-dom";
import UserDropdown from "./UserDropdown";

export default function Navbar({ name }) {
  console.log("Rendering: Navbar");

  return (
    <>
      <div className="navbar bg-base-100 drop-shadow-sm">
        <div className="flex-1">
          <Link
            to="/"
            className="btn btn-ghost normal-case text-md md:text-xl px-2 gap-1"
          >
            <img src={Logo} className="h-6" alt="" />
            Resources
          </Link>
        </div>

        <UserDropdown name={name} />
      </div>
    </>
  );
}

Представьте себе, как сложно поддерживать приложение React с разными уровнями компонентов, передающими и отображающими одно и то же состояние.

Растущая сложность и качество кода

При использовании useState и props в качестве единственного средства управления состоянием в приложении реагирования кодовая база может быстро усложниться, и вам придется управлять десятками или сотнями переменных состояния, которые могут быть дубликатами друг друга, разбросаны по разным файлам и компоненты могут быть довольно сложными, любое изменение данной переменной состояния потребует тщательного рассмотрения зависимостей между компонентами, чтобы избежать любого потенциального дополнительного рендеринга в и без того медленном приложении.

Второй подход: контекстный API

Context API — это попытка React решить недостатки использования только реквизитов и useState для управления состоянием, в частности, контекстный API является ответом на ранее упомянутую проблему, связанную с необходимостью передавать реквизиты по всему дереву компонентов. Используя контекст, вы можете определить состояние данных, которые вы считаете глобальными, и получить доступ к их состоянию из любой точки дерева компонентов: больше не нужно углубляться в детали.

Важно отметить, что контекстный API изначально был задуман для решения проблемы глобального обмена данными (такими данными, как темы пользовательского интерфейса, информация аутентификации, которая является нашим вариантом использования, языками и т. д.), для других типов данных, которые необходимо совместно использовать. среди более чем одного компонента, но не обязательно является глобальным для всего приложения, контекст может быть не лучшим вариантом, в зависимости от варианта использования вы можете рассмотреть другие методы, такие как композиция компонентов, что выходит за рамки этой статьи.

Переключение в контекст

Создание контекста аутентификации

Функция createContext проста: она создает новую переменную контекста и принимает один необязательный параметр: значение контекстной переменной по умолчанию.

Давайте посмотрим на это в действии: сначала создайте новую папку «contexts» и новый файл внутри нее «Auth.jsx». Чтобы создать новый контекст, нам нужно вызвать функцию createContext(), присвоить возвращаемое значение новой переменной Auth, которая затем будет экспортирована:

./src/contexts/Auth.jsx

import { createContext } from "react";

export const Auth = createContext();

Предоставьте контекст аутентификации

Теперь нам нужно предоставить переменную контекста «Auth», которую мы создали ранее. Для этого мы используем поставщика контекста, поставщик контекста — это компонент, который имеет свойство «значение», мы можем использовать это свойство для совместного использования значения — имени. – по всему дереву компонентов, обертывая дерево компонентов компонентом-поставщиком, мы делаем это значение доступным из любого места внутри дерева компонентов без необходимости передавать это свойство каждому дочернему компоненту индивидуально.

В нашем примере аутентификации нам нужна переменная для хранения объекта пользователя и какой-то метод установки для управления этой переменной состояния. Это идеальный вариант использования useState. При использовании контекста вам необходимо убедиться, что вы определяете данные, которые хотите предоставить, и передаете эти данные (в нашем примере пользователя) во все вложенное внутрь дерево компонентов, поэтому определите новую переменную состояния user внутри компонента поставщика и наконец, мы передаем и пользователя, и setUser внутри массива в качестве значения, которое поставщик предоставит дереву компонентов:

./src/contexts/Auth.jsx

import { createContext, useState } from "react";

export const Auth = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  return <Auth.Provider value={[user, setUser]}>{children}</Auth.Provider>;
};

Еще мы можем переместить нашу переменную состояния «name» из основного компонента приложения в контекст Auth и предоставить ее вложенным компонентам:

import { createContext, useState } from "react";

export const Auth = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [name, setName] = useState("CLA");
  return <Auth.Provider value={[name, setName]}>{children}</Auth.Provider>;
};

Теперь все, что осталось, — это вложить наше приложение в тот же компонент AuthProvider, который мы только что экспортировали.

./src/main.jsx:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { AuthProvider } from "./contexts/Auth";

import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
  <AuthProvider>
    <App />
  </AuthProvider>
);

Поскольку мы отображаем свойство Children внутри Auth.Provider, все элементы, вложенные в компонент AuthProvider, теперь могут использовать свойство value, которое мы передали в Auth.Provider. Это может показаться запутанным, но как только вы поэкспериментируете с этим, попробуйте предоставить и использовать глобальное состояние Context. В конце концов, для меня это приобрело смысл только после экспериментов с Context API.

Использование контекста аутентификации

Последний шаг прост: мы используем контекстный хук «useContext» для доступа к значению, которое предоставляет поставщик контекста «Auth», который в нашем случае представляет собой массив, содержащий пользователя и setUser. В следующем коде мы можем используйте useContext для использования контекста аутентификации внутри навигационной панели. Это возможно только потому, что Navbar вложен внутри компонента App, а поскольку AuthProvider окружает компонент App, свойство value можно использовать только с помощью перехватчика useContext. Еще один замечательный инструмент, который React предоставляет «из коробки» для управления любыми данными, к которым можно получить глобальный доступ, а также манипулировать ими с помощью любого потребительского компонента.

./src/компоненты/Navbar.jsx

export default function Navbar() {
 const [name, setName] = useContext(Auth);
 console.log(name)

 return (...)};

Обратите внимание, что мы больше не принимаем никаких реквизитов в функциональном компоненте Navbar(). Вместо этого мы используем useContext(Auth) для использования контекста Auth, захватывая и имя, и setName. Это также означает, что нам больше не нужно передавать свойство в Navbar:

./src/App.jsx

// ... //
return (
   <BrowserRouter>
     <div className="h-screen">
       <Navbar/> // no need to pass prop anymore
// ... //

Обновление контекста аутентификации

Мы также можем использовать предоставленную функцию setName для управления переменной состояния «name»:

./src/pages/EditUser.jsx

export default function EditUser() { // no need to accept props anymore
 const [name, setName] = useContext(Auth); // grabbing the name and setName variables from Auth context
 console.log("Rendering: EditUser");

Представляем хук useReducer()

В предыдущем примере мы использовали контекстный API для управления и обмена нашим состоянием по дереву компонентов. Вы могли заметить, что мы все еще используем useState в качестве основы нашей логики, и это в основном нормально, поскольку наше состояние по-прежнему является простым объектом. на этом этапе, но если мы хотим расширить возможности нашего потока аутентификации, нам определенно потребуется хранить больше, чем просто адрес электронной почты пользователя, вошедшего в систему в данный момент, и здесь мы возвращаемся к ограничениям, с которыми мы ранее столкнулись в отношении использование useState со сложным состоянием, к счастью, React решает эту проблему, предоставляя альтернативу useState для управления сложным состоянием: введите useReducer.

useReducer можно рассматривать как обобщенную версию useState, он принимает два параметра: функцию редуктора и начальное состояние.

В начальном состоянии нет ничего интересного, волшебство происходит внутри функции редуктора: он проверяет тип произошедшего действия, и в зависимости от этого действия редуктор определит, какие обновления применить к состоянию, и вернет его новое значение. .

В приведенном ниже коде функция редуктора имеет два возможных типа действий:

  • «LOGIN»: в этом случае состояние пользователя будет обновлено новыми учетными данными пользователя, указанными в полезных данных действия.

  • «ВЫХОД»: в этом случае состояние пользователя будет удалено из локального хранилища и возвращено в нулевое значение.

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

Наконец, хук useReducer возвращает текущее состояние и функцию отправки, которую мы используем для передачи действия в редуктор.

В остальном логика идентична предыдущему примеру:

./src/contexts/Auth.jsx

import { createContext, useEffect, useReducer, useState } from "react";

export const Auth = createContext();
import { createContext, useReducer } from "react";

export const Auth = createContext();
const reducer = (state, action) => {
  switch (action.type) {
    case "LOGIN":
      return { user: action.payload };

    case "LOGOUT":
      localStorage.removeItem("user");
      return { user: null };

    default:
      break;
  }
};

export const AuthProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, {
    user: null,
  });

  return (
    <Auth.Provider value={{ ...state, dispatch }}>{children}</Auth.Provider>
  );
};

Отправка действий вместо использования функции установки setState – например: setName –

Как мы только что упомянули, мы используем функцию диспетчеризации для передачи действия редуктору. В следующем коде мы инициируем действие ВХОД и предоставляем адрес электронной почты пользователя в качестве полезной нагрузки, теперь состояние пользователя обновится, и это изменение сработает. повторный рендеринг всех компонентов, подписанных на пользовательское состояние. Важно отметить, что повторный рендеринг будет запущен только в том случае, если произойдет фактическое изменение состояния, а не повторный рендеринг, если редуктор возвращает то же предыдущее состояние.

export default function Login() {
 const { dispatch } = useContext(Auth);


 const handleLogin = async (e) => {
   // Updating the global Auth context
   dispatch({ type: "LOGIN", payload: {email: email.current.value} });
 };

 return (...)};

Логин пользователя

JWT Local storage

Совет профессионала

Обратите внимание, что объект пользователя, который мы получаем после успешного входа в систему, теперь сохраняется в localStorage.

Пользовательский крючок для входа в систему

Теперь, когда мы хорошо разбираемся в useReducer, мы можем далее инкапсулировать нашу логику входа и выхода в отдельные пользовательские перехватчики. С помощью одного вызова перехватчика входа в систему мы можем обрабатывать вызов API к маршруту входа в систему, получать нового пользователя. учетные данные и сохраните их в локальном хранилище, отправьте вызов LOGIN для обновления состояния пользователя, одновременно занимаясь обработкой ошибок:

./src/hooks/useLogin.jsx

import { useContext, useState } from "react";
import { Auth } from "../contexts/Auth";

export const useLogin = () => {
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  const { dispatch } = useContext(Auth);

  const login = async (email, password) => {
    setIsLoading(true);
    setError(null);

    try {
      const response = await fetch("/api/users/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email, password }),
      });

      const json = await response.json();

      if (json.name === "Error") {
        setError(json.message);
        setIsLoading(false);
      }

      if (!response.ok) {
        setIsLoading(false);
        setError(json);
      }

      if (response.ok) {
        // Save the user and token in the localstorage
        localStorage.setItem("user", JSON.stringify(json));

        // Updating the global Auth context
        dispatch({ type: "LOGIN", payload: json });

        setIsLoading(false);
      }
    } catch (error) {
      console.log(error);
    }
  };

  return { error, isLoading, login };
};

Примечание. Более продвинутым пользователям React среди читателей может быть интересно, почему мы не использовали функцию ленивой инициализации useReducer для получения учетных данных пользователя. useReducer принимает третий необязательный параметр, называемый функцией инициализации, эта функция используется в случае, если нам нужно применить некоторую логику, прежде чем мы сможем получить начальное значение состояния. Причина, по которой мы не выбрали этот вариант, заключается в простом разделении задач, код таким образом проще понять и, как следствие, проще поддерживать .

Страница авторизации

Вот как выглядит верхняя часть нашей страницы входа после использования перехватчика useLogin() для извлечения функции входа и вызова функции входа с учетными данными, предоставленными пользователем:

// ... ... //
export default function Login() {
 const { login, isLoading, error } = useLogin();
 console.log("Rendering: Login");
 const email = createRef(null);
 const password = createRef(null);

 const handleLogin = async (e) => {
   await login(email.current.value, password.current.value);
 };
 return (...)
// ... ... //

Мы также отключаем функцию отправки, когда пользователь отправляет форму:

<button
  onClick={handleLogin}
  disabled={isLoading}
  className="btn btn-square w-full bg-gray-100 text-gray-600 hover:bg-gray-300 border-none"
>
  {isLoading && "A moment please!"}
  {!isLoading && "Login"}
</button>

И рендеринг любых ошибок аутентификации, которые мы получаем от нашего бэкэнда:

{
  error && <span className="text-red-500 p-2">{error.message}</span>;
}

Rendering Errors

Сохранение состояния пользователя

Вам может быть интересно, зачем нам хранить объект пользователя в localStorage. Проще говоря, мы хотим, чтобы пользователь вошел в систему до тех пор, пока срок действия токена не истечет. Использование localStorage — отличный способ хранить фрагменты JSON, как в нашем примере. Обратите внимание, как состояние стирается, если вы обновляете страницу после входа в систему. Эту проблему можно легко решить, используя перехват useEffect, чтобы проверить, есть ли у нас сохраненный объект пользователя в localStorage. Если он есть, мы автоматически авторизуем пользователя:

// ... ... //
export const AuthProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, {
    user: null,
  });

  useEffect(() => {
    const user = JSON.parse(localStorage.getItem("user"));

    if (user) {
      return dispatch({ type: "LOGIN", payload: user });
    }
  }, []);

  return (
    <Auth.Provider value={{ ...state, dispatch }}>{children}</Auth.Provider>
  );
};

Пользовательские перехватчики для выхода из системы

То же самое относится и к перехватчику выхода из системы: здесь мы отправляем действие ВЫХОД из системы, чтобы удалить текущие учетные данные пользователя как из состояния, так и из локального хранилища:

./src/hooks/useLogout.jsx

import { useContext } from "react";
import { Auth } from "../contexts/Auth";

export const useLogout = () => {
  const { dispatch } = useContext(Auth);

  const logout = () => {
    // delete user from the localstorage
    localStorage.removeItem("user");
    // Wipe out the Auth context (user:null) / dipatch 'LOGOUT'
    dispatch({ type: "LOGOUT" });
  };

  return { logout };
};

Выход пользователя

Чтобы выйти из системы, давайте добавим событие щелчка к кнопке «Выход», расположенной в UserDropdown.jsx, и обработаем его соответствующим образом:

./src/компоненты/UserDropdown.jsx

// Extracting the logout function from useLogout() and handling the click event listener //
export default function UserDropdown() {
 const { user } = useContext(Auth);
 const { logout } = useLogout();
 console.log("Rendering: UserDropdown");

 const handleLogout = () => {
   logout();
 };
// ... ... //

// Adding a click event listener to logout button //
<li>
   <button onClick={handleLogout}>Logout</button>
</li>
// ... ... //

User Logout

Защита маршрутов React

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

Мы достигаем этого с помощью библиотеки реагирования-маршрутизатора-dom, определяя 2 маршрута: «/» и «/login», мы контролируем, какой компонент отображать на каждом маршруте, используя глобальное состояние аутентификации., значение auth, равное нулю, представляет неаутентифицированного пользователя и наоборот:

./src/App.jsx

import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
import "./App.css";
import Navbar from "./components/Navbar";
import Home from "./pages/Home";
import Login from "./pages/Login";
import { useContext } from "react";
import { Auth } from "./contexts/Auth";

function App() {
  const { user } = useContext(Auth);
  return (
    <BrowserRouter>
      <div className="h-screen">
        <Navbar />
        <main className="px-4">
          <Routes>
            <Route
              path="/"
              element={user ? <Home /> : <Navigate to="/login" />}
            />
            <Route
              path="/login"
              element={!user ? <Login /> : <Navigate to="/" />}
            />
          </Routes>
        </main>
      </div>
    </BrowserRouter>
  );
}

export default App;

Резюме диаграммы

Diagram

Заворачивать

В этой статье мы попытались рассмотреть простой, но очень распространенный вариант реализации управления состоянием рабочего процесса аутентификации, рассмотрев различные подходы, обоснование каждого из них и их компромиссы. Управление состоянием в клиентских фреймворках и в React в частности — одна из самых обсуждаемых тем в сообществе фронтенд-разработчиков просто потому, что оно может либо улучшить, либо ухудшить производительность и масштабируемость вашего приложения. Огромное количество различных методов, шаблонов, библиотек и инструментов, которые пытаются решить проблему управления состоянием, огромно. Наша цель состояла в том, чтобы дать вам четкое представление о методах, чтобы вы могли реализовать их в своем собственном приложении для более продвинутых пользователей. методы и шаблоны управления состоянием в более сложных приложениях, ознакомьтесь с нашей следующей статьей, где мы рассмотрим Redux для масштабируемого управления состоянием в React.

Вскоре

ContextAPI против набора инструментов Redux

Redux был принят сообществом за много лет до появления набора инструментов Redux. Фактически, RTK был представлен в качестве стартового шаблона для начальной загрузки управления состоянием Redux в новых приложениях (в октябре 2019 года его первоначальное название было «redux-starter-kit»), хотя сегодня между сопровождающими Redux и сообществом существует общий консенсус в отношении того, что набор инструментов Redux является допустимым способом работы с Redux. RTX абстрагирует большую часть логики Redux, что делает его более простым в использовании, с гораздо меньшим количеством многословия и побуждает разработчиков следовать лучшим практикам, одно из основных различий между ними заключается в том, что Redux был создан, чтобы быть беспристрастным, предоставляя минимальный API и ожидая, что разработчики сделают большую часть тяжелой работы, написав свои собственные библиотеки для общих задач и разобравшись со структурой кода, это привело к медленной разработке и беспорядочному коду. Инструментарий Redux был добавлен в качестве дополнительного уровня абстракции, не позволяя разработчикам попадать в его распространенные ловушки. Дополнительную информацию и рассуждения от его сопровождающих можно найти в официальной документации здесь.


Career Services background pattern

Карьерные услуги

Contact Section background image

Давай останемся на связи

Code Labs Academy © 2024 Все права защищены.