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

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

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

З цим розширенням можливостей з’явилася концепція керування станом, оскільки складність програм на стороні клієнта зростає, потреба у збереженні локального стану зростає й стає вузьким місцем сама по собі, якщо її не обробляти належним чином і не враховувати масштабованість.

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

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

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

Посилання для попереднього перегляду доступне тут.

Розглянемо випадок, коли ми реалізуємо процес автентифікації для програми React.

User Login

Як показано на GIF вище, ми хочемо дозволити користувачам входити або реєструватися в нашій програмі за допомогою облікових даних. Якщо було надано дійсні облікові дані, користувач увійде в систему, програма автоматично перейде на домашню сторінку, і користувач зможе продовжити використання програми.

Подібним чином, якщо користувач виходить із системи, ресурси домашньої сторінки будуть захищені за входом, сторінка входу буде єдиною сторінкою, доступною для користувача.

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

State

Як показано на ілюстрації вище, ми хочемо, щоб компонент програми враховував поточний стан і відображав лише одну з двох сторінок – домашню сторінку або сторінку входу – на основі поточного стану.

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

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

Репозиторій проекту містить зразок серверної програми, який ми використовуватимемо для реалізації інтерфейсної сторони (ми не будемо вдаватися в це, оскільки це не головна увага, але код навмисно був простим, тому у вас не виникне труднощів із ним )

Ми починаємо зі створення наступних сторінок і компонентів:

  • Домашня сторінка

  • Сторінка входу

  • Сторінка EditUser

  • Компонент Navbar

— Компонент UserDropdown

Додаток React з кількома сторінками потребує належної навігації, для цього ми можемо використовувати react-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

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

Попередній перегляд має виглядати приблизно так:

Changing user name

Ім’я, яке відображається на панелі навігації (верхня права частина), є змінною стану, визначеною в головному компоненті програми. Та сама змінна передається на панель навігації та домашню сторінку. Проста форма, використана вище, фактично оновлює змінну стану «name» з компонента EditPage.

Два підходи, наведені нижче, детально описуватимуть реалізацію:

Перший підхід: useState

useState()

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

Як щодо того, щоб ми побачили це в дії? Ім’я, яке відображається на панелі навігації (верхня права частина), є змінною стану, визначеною в головному компоненті програми. Та сама змінна передається на панель навігації та домашню сторінку. Проста форма, використана вище, фактично оновлює змінну стану «name» з компонента EditPage. Підсумок такий: useState — це основний хук, який приймає початковий стан як параметр і повертає дві змінні з двома значеннями, змінну стану, що містить початковий стан, і функцію встановлення для тієї самої змінної стану.

Давайте розберемо це та подивимося, як це було реалізовано в першу чергу.

  1. Створення змінної стану «name»:

./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 (...)};

Реквізит

Props є одним із основних будівельних блоків компонента react, концептуально, якщо ви думаєте про функціональний компонент React як про функцію Javascript, тоді props — це не більше, ніж параметри функції, поєднання props і хука useState може запропонувати вам надійну структуру для керування станом простої програми React.

Реквизити React передаються як атрибути користувацьким компонентам. Атрибути, передані як props, можуть бути деструктуровані з об’єкта props, приймаючи його як аргумент, подібно до цього:

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

<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>

Реквізити можна приймати та використовувати всередині функціонального компонента, подібно до аргументів звичайної функції. Саме тому, що «name» передається як властивість компоненту 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/components/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 як єдиного засобу керування станом у додатку React кодова база може швидко ускладнюватися, доводиться керувати десятками чи сотнями змінних стану, які можуть бути дублікатами одна одної, розкиданими по різних файлах і компоненти можуть бути досить складними, будь-яка зміна даної змінної стану вимагатиме ретельного розгляду залежностей між компонентами, щоб уникнути будь-якого потенційного додаткового повторного рендерингу в і без того повільній програмі.

Другий підхід: контекстний API

Контекстний 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. Використовуючи Context, вам потрібно переконатися, що ви визначаєте дані, які хочете надати, і передаєте ці дані (користувач у нашому прикладі) до всього вкладеного дерева компонентів, тому визначте нову змінну стану user у компоненті провайдера та нарешті, ми передаємо як 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>;
};

Інша річ, яку ми можемо зробити, це перемістити нашу змінну стану «ім’я» з основного компонента програми в контекст авторизації та надати її вкладеним компонентам:

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>
);

Оскільки ми відтворюємо дочірню характеристику всередині Auth.Provider, усі елементи, вкладені в компонент AuthProvider, тепер можуть використовувати властивість значення, яку ми передали в Auth.Provider. Це може здатися заплутаним, але як тільки ви поекспериментуєте з цим, спробуйте надати та споживати глобальний - Context - стан. Зрештою, для мене це стало сенсом лише після експериментів із Context API.

Використання контексту авторизації

Останній крок простий: ми використовуємо хук контексту "useContext", щоб отримати доступ до значення, яке надає постачальник контексту "Auth", яке в нашому випадку є масивом, що містить користувача та setUser, у наступному коді ми можемо використовуйте useContext для використання контексту Auth всередині Navbar. Це можливо лише тому, що Navbar вкладено в компонент App, а оскільки AuthProvider обгортає компонент App, властивість значення може використовуватися лише за допомогою хука useContext. Ще один приголомшливий інструмент, який React надає з коробки для керування будь-якими даними, до яких можна отримати глобальний доступ, а також маніпулювати будь-яким компонентом споживача.

./src/components/Navbar.jsx

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

 return (...)};

Зверніть увагу, що ми більше не приймаємо жодних пропів у функціональному компоненті Navbar(). Натомість ми використовуємо useContext(Auth), щоб використати контекст Auth, захоплюючи як name, так і 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, він приймає два параметри: функцію редуктора та початковий стан.

Нічого цікавого для початкового стану, магія відбувається всередині функції редуктора: вона перевіряє тип дії, яка сталася, і залежно від цієї дії редуктор визначатиме, які оновлення застосовувати до стану, і повертатиме його нове значення .

Дивлячись на наведений нижче код, функція редуктора має два можливі типи дій:

  • «ЛОГІН»: у цьому випадку стан користувача буде оновлено за допомогою нових облікових даних користувача, наданих у корисному навантаженні дії.

  • "ВИХІД": у цьому випадку стан користувача буде видалено з локального сховища та повернено до нульового значення.

Важливо зазначити, що об’єкт дії містить як поле типу, яке визначає, яку логіку застосовувати, так і необов’язкове поле корисного навантаження для надання даних, необхідних для застосування цієї логіки.

Нарешті, хук 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 –

Як ми щойно згадували, ми використовуємо функцію диспетчеризації, щоб передати дію редюсеру. У наступному коді ми ініціюємо дію LOGIN і надаємо електронну адресу користувача як корисне навантаження, тепер стан користувача буде оновлено, і ця зміна запустить повторне відтворення всіх компонентів, підписаних на стан користувача. Важливо зазначити, що повторна візуалізація буде ініційована, лише якщо станеться фактична зміна стану, жодної повторної візуалізації, якщо редуктор повертає той самий попередній стан.

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, ми можемо далі інкапсулювати нашу логіку входу та виходу в їхні власні окремі користувацькі хуки, за допомогою одного виклику хука Login ми можемо обробляти виклик 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 приймає третій необов’язковий параметр, який називається функцією init, ця функція використовується у випадку, якщо нам потрібно застосувати певну логіку, перш ніж ми зможемо отримати початкове значення стану. Причина, чому ми не вибрали це, полягає в простому розділенні завдань, код таким чином легше зрозуміти і, як наслідок, легше підтримувати .

Сторінка входу

Ось як виглядає верхня частина нашої сторінки входу після використання хука 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/components/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

Останнім кроком у реалізації нашої програми є використання глобального стану користувача для керування навігацією користувача, швидкого нагадування про те, якої поведінки ми повинні досягти: спочатку користувача вітає сторінка входу, з цього моменту користувач може отримати доступ лише до домашньої сторінки після успішного входу, так само користувач буде перенаправлено на сторінку входу після виходу.

Ми досягаємо цього за допомогою бібліотеки react-router-dom, визначаючи 2 маршрути: "/" та "/login", ми контролюємо, який компонент відображати на кожному маршруті за допомогою глобального стану авторизації, автентифікація, яка має значення null, означає неавтентифікованого користувача і навпаки:

./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 Toolkit

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


Career Services background pattern

Кар'єрні послуги

Contact Section background image

Давайте залишатися на зв'язку

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