Перед тем как знакомиться с новым материалом, я рекомендую вам посмотреть основы в моем блоге и на гитхабе в моих переводах:
Обязательно прочитайте:
- Redux - простое руководство.
- Как использовать Redux в ReactJS с реальными примерами.
- React . Детальный обзор Context API
- React. Как использовать «useContext» в React Hooks
- Передача данных между родственными компонентами в React с использованием Context API и React Hooks.
- React хуки и функциональные компоненты.
- Шаблоны React.
Redux - это библиотека, которая помогает управлять состоянием вашего приложения.
Redux следует использовать в средних и больших одностраничных приложениях со сложным потоком данных.
Redux может добавить ненужную сложность вашему приложению, если оно действительно маленькое с простым потоком данных.
С другой стороны, в версии 16.3 React команда представила Context, который также помогает управлять состоянием React - приложения.
Зачем нам нужен инструмент управления состоянием - state
Если у нас есть несколько компонентов, которые совместно используют один и тот же фрагмент данных, и у них нет родительских и дочерних отношений, то для решения проблемы используют Redux. В Redux у нас есть один фрагмент идентичных данных (identical data), который синхронизирован со всеми компонентами, которые используют этот фрагмент данных.Одним из решений может быть использование event raising в Angular и использование props в React. Позже в большом коде это решение превратится в спагетти событий ( event spaghetti) и в React - приложении, мы будем сталкиваться с проблемой получения (доступности) props - так называемым - prop drilling.
Со всей базы кода мы начнем получать события, и будет сложно отслеживать их все. Таким образом, поток данных становится непредсказуемым. Facebook столкнулся с этой проблемой еще в 2014 году, поэтому они представили Flux Architecture.
Redux - это упрощенная и легкая реализация Flux Architecture.
Основные преимущества Redux
- Отделенная, расцепленная архитектура
- Тестируемость
- Отличная поддержка инструментов в Chrome, Firefox
- Простая реализация функций отмены / повтора - выкл./вкл.
Когда использовать Redux
В следующих случаях мы можем использовать redux:- Один и тот же фрагмент данных в нескольких местах
- Несколько (views) - представлений, которые должны работать с теми же данными в синхронизации
- Данные могут быть изменены несколькими действиями / несколькими пользователями
Прежде чем мы получим
context
, для решения проблемы использовали redux, такой как спагетти - event spaghetti и prop drilling. Redux приносит много сложности для простых приложений. Позже React - команда представила контекстную концепцию для простоты.
С помощью контекста - context мы можем передавать данные по нашему дереву компонентов без prop drilling. Таким образом, в одном компоненте мы предоставим некоторый контекст или общие данные, а в другом компоненте мы будем использовать данные.
Теперь мы увидим, как мы можем использовать контекст поддерживаемым и инкапсулированным образом с помощью typescript и React - хуков. В нашем примере мы будем использовать понятия действий -
actions
, редуктора - reducer
и состояния - state
из redux. Итак, сначала мы рассмотрим основные концепции Redux.
Основная концепция Redux
- Хранилище -
Store
- один объект JS, который содержит состояние приложения. - Действия -
Actions
- Обычный объект JS, представляющий, что что-то произошло. Подобные события. - Редуктор
Reducer
- функция, которая определяет, как состояниеstate
изменяется в ответ на действие -action
. Это не меняет состояние. Возвращает новое состояние.
{type: ‘USER_LOGGED_IN’}
В Redux мы не обновляем напрямую состояние. Сначала мы отправим действие (action
). Оно попадет в хранилище (store
). Хранилище (store
) передает действие (action
) корневому редуктор (reducer
). На основе действия редуктор (reducer
) возвращает новое состояние (state
), и хранилище (store
) обновляется внутри.
На картинке показано изменение состояния компонента при клике
Использование контекста в приложении React
Для демонстрации идея состоит в том, чтобы создать компонент ,mark>Header, который будет отвечать за отображение кнопки «Вход» или «Выход из системы» в зависимости от состояния из хранилища -store
. Мы отправим действие action
LOGIN и LOGOUT из компонента Header.
Мы сделаем все 5 простых шагов.
- Create Actions - Создать действия
- Create State - Создадим состояние
- Create Reducer - Создадим редуктор
- Create Context - Создадим контекст
- Create Header component - Создадим сам компонент Header
1 - Создание действий - Actions
Сначала мы должны определить некоторые действия, которые будут отвечать за изменение состояния нашего приложения. У нас есть два действия "Войти" и "Выйти".
Action.ts
export enum Action { LOGIN = "LOGIN", LOGOUT = "LOGOUT" }
Создание состояния - State
Теперь мы должны определить, какие данные мы хотим сохранить в нашем хранилище контекста. Поэтому мы создадим интерфейс для этого, а также начальное значение для состояния. В нашем случае мы просто сохраним имя пользователя.
state.ts
export interface StateType { username: string | null; } export const initialState: StateType = { username: null };
Создание редуктора - Reducer
Pure Function или Чистая функция - это такая функция, которая при получении однинх и тех же данных на входе, всегда получаем один и тот же выход из функции, то функция является чистой функцией. Так что побочных эффектов не будет. Это дает нам легкую тестируемость и простой способ реализации функций отмены / возврата.
Если вы забыли некоторые возможности JavaScript, то я рекомендую вам посмотреть статьи в моем блоге -
ES6 и JS
Далее мы создадим редуктор. Редуктор это чистая функция. Это функция с двумя аргументами. Первый - это состояние по умолчанию с типом StateType
, а второй - объект с props- свойствами type
и полезной нагрузки - payload
. Свойство type
определяет тип действия, а payload
содержит дополнительные данные от диспетчера.
Reducer.ts
import { StateType, initialState } from "./state"; import { Action } from "./Action"; export type ActionType = { type: Action; payload?: StateType; }; const reducer = (state: StateType, { type, payload }: ActionType) => { switch (type) { case Action.LOGIN: return { ...state, ...payload }; case Action.LOGOUT: return initialState; default: return state; } }; export default reducer;
Для
action
-действия LOGIN мы передадим имя пользователя в качестве полезной нагрузки - payload
, когда мы отправим действие - action
. Для выхода из системы нам не нужны никакие данные в качестве полезной нагрузки -payload
. Мы просто сбросим состояние до начального значения state
.
4 - Создадим контекст -Context
Теперь мы создадим контекст. Сначала мы определим ContextType
, а затем создадим Store
. После этого мы создадим StoreProvider
.
Context.tsx
import React, { createContext, Dispatch, useReducer } from "react"; import reducer, { ActionType } from "./Reducer"; import { StateType, initialState } from "./state"; export interface ContextType { state: StateType; dispatch: Dispatch<ActionType>; } export const RootStore = createContext({} as ContextType); export const RootStoreProvider: React.FC = ({ children }) => { const [state, dispatch] = useReducer<React.Reducer<StateType, ActionType>>(reducer, initialState); const value = { state, dispatch }; return <RootStore.Provider value={value}>{children}</RootStore.Provider>; };
Теперь мы обернем наш корневой компонент этим
RootStoreProvider
для доступа к хранилищу - store
глобально.
index.tsx
const App = () => { return <RootStoreProvider>....</RootStoreProvider>; };
Теперь у нас все готово. Мы создадим простой компонент Header, из которого мы будем использовать
RootStore
для получения информации о пользователе, а также для обновления информации.
5 - Создадим сам компонент Header
Header/index.tsx
import React from "react"; const Header = () => { const username = null; const toggleLoginLogoutHandler = () => {}; return ( <div style={{ backgroundColor: "#dee5ec", padding: 10, display: "flex", justifyContent: "space-between", }} > <div> <p>Header</p> {username && <p>Logged in as {username}</p>} </div> <button onClick={toggleLoginLogoutHandler}> {username ? "Logout" : "Login"} </button> </div> ); }; export default Header;
Теперь мы будем использовать наш
RootStore
для получения имени пользователя, а также для отправки действий по входу и выходу из системы.
import React, { useContext } from "react"; import { RootStore } from "../../Context"; import { Action } from "../../Action"; const Header = () => { const { state: { username }, dispatch } = useContext(RootStore); const toggleLoginLogoutHandler = () => { if (username) { dispatch({ type: Action.LOGOUT }); } else { dispatch({ type: Action.LOGIN, payload: { username: "Ashraful" } }); } }; .......
Наконец, обновите корневой компонент.
....... import Header from "./src/components/Header"; const App = () => { return ( <RootStoreProvider> <Header /> </RootStoreProvider> ); };
Вот и все. Мы внедрили React context со всеми концепциями Redux - компонентов. Вот ссылка на полный код.
Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook. Пишите мне - kolesnikovy70 почта gmail.com
Удачного кодирования!
Комментариев нет:
Отправить комментарий