Что нужно знать о Redux - action/dispatch/reducer/store

2 года назад·3 мин. на чтение

В этой статье рассмотрим работу с Redux - его основные понятия, и как Redux работает с данными.

Redux - это стэйт менеджер для JS приложений. Он может работать не только в React приложениях. Просто так сложилось исторически, что они часто упоминаются вместе. Redux хранит состояние в дереве объектов внутри единого стора. Единственная возможность изменить состояние - отправить action. Action это объект, который описывает действие. Он как бы отвечает на вопрос "Что я хочу изменить в состоянии?".
// types.js
const ADD_TODO = "ADD_TODO"
// actions.js
import { ADD_TODO } from "./types.js"

export const addTodoAction = {
  type: ADD_TODO,
  payload: {
     id: 1,
     text: "Изучить Redux",
     done: false
   }
}
Далее action попадает в reducer, где описано как состояние должно быть изменено ("Как я хочу изменить состояние?").
//  todo-reducer.js
import { ADD_TODO } from "./types.js"

export const todoReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO: {
      const item = action.payload
      return [...state, item]
    }
    default:
      return state
  }
}

Для чего нужен Redux?

Redux и в целом любая другая система работы с состоянием нужна для контроля над состоянием. Веб приложения усложняются, добавляются новые фичи и контроль над приложением теряется. Становится сложно охватывать большой проект как единое целое. Становится cложно передавать изменения. Встроенными способами в React их приходилось бы передавать по цепочке от одного компонента в другой или через Context API. По дороге обновленное состояние может также влиять на другие компоненты и т.д. И такая бесконтрольность расползается по всему проекту и может послужить появлению новых багов и добавит сложность в отладке. Теряется прозрачность того что происходит.
Action’ы добавляют порядок в происходящие изменения. Action - это объект, и его можно залогировать и последовательно отслеживать как меняется состояние. Подытожив, можно вывести три принципа Redux:
  • Единственный источник правды - единый стор, который меняются и всегда содержит актуальные данные.
  • Состояние - только для чтения. Нельзя менять его напрямую - только через action’ы.
  • Изменения делаются только при помощи чистых функций.
  • Эти функции (редьюсеры) принимают в качестве аргумента старое состояние и возвращают обновленное состояние. И всегда при одних и тех же данных результат этих функций будет одинаков.

Понятия в Redux

Action

Action (экшн) - это источник данных в стор, Action включает тип и некоторую информацию (payload). Тип обычно имеет строковое значение. Он нужен чтобы reducer понимал какой action был отправлен. Далее к стору будет применен payload.

Reducer

Reducer (редьюсер) - это функция, которая определяет как должно меняться состояние в зависимости от аction’а. Редьюсеры должны быть чистым функциями - они должны вычислить следующее состояние и вернуть новый объект состояния. Никаких сайд эффектов, мутаций состояния, и вызовов API в редьюсере быть не должно.

Store

Store - объединяет аction’ы и редьюсеры
  • Хранит состояние приложения.
  • Предоставляет доступ к состоянию через getState.
  • Позволяет изменять состояние через dispatch.
  • Регистрирует подписчиков через subscribe.
Теперь когда мы знаем основные понятия сформулируем флоу - движение данных в Redux. Сначала вызываем функцию dispatch, передав в нее action.
// App.jsx
import { useDispatch } from "react-redux"
import { ADD_TODO } from "./types.js"

export default App() {
  const dispatch = useDispatch()
 
  const handleTodoAdd = () => {
    dispatch({
      type: ADD_TODO,
       payload: {
         id: 1,
         text: "Изучить Redux",
         done: false
       },
    })
  }

  return (
    <button type="button" onClick={handleTodoAdd}>Добавить todo</button>
  )
}
Далее Redux вызывает переданный в него редьюсер. В редьюсер отправляется два аргумента - текущее состояние (state) и action.
//  todo-reducer.js
import { ADD_TODO } from "./types.js"

export const todoReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO: {
      const item = action.payload
      return [...state, item]
    }
    default:
      return state
  }
}
Redux сохраняет весь объект, который вернулся из корневого редьюсера. Почему редьюсер - корневой? В Redux передается один редьюсер, но его можно разделить на несколько и собрать вместе при помощи combineReducers. Результатом этой функции будет корневой редьюсер. Обычно это делается, когда в приложении есть несколько модулей и есть смысл разделить большой редьюсер на несколько маленьких. Но для мелких приложений это совсем не обязательно.
// reducers.js
import { combineReducers } from "redux"
import { todoReducer } from "./todo-reducer"

export const rootReducer = combineReducers({
  todos: todoReducer,
})
Как уже упоминалось, Redux работает не только с ReactJS. Это универсальный инструмент. Однако для того чтобы использовать его в ReactJS нужен специальный байндинг, который ставится как отдельный пакет - react-redux.

Как подключить Redux к ReactJS проекту

Установить Redux с помощью команды.
npm i redux react-redux
Проинициализировать store и обернуть приложение тегом <Provider> c переданным в него объектом store.
// index.js
import React from "react"
import ReactDOM from "react-dom/client"

import { createStore } from "redux"
import { Provider } from "react-redux"

import App from "./App"
import { rootReducer } from "./reducers"

const store = createStore(rootReducer)

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

Подробное руководство по микрофронтенд архитектуре

год назад·2 мин. на чтение

Микрофронтенд становится популярной архитектурой, компании растут, появляется необходимость масштабировать команды.

Микрофронтенд - это архитектура, которая позволяет масштабироваться, делать команды независимыми и больше ориентироваться на бизнес потребности. Мы начинаем большую и подробную серию видео о микрофронтенд архитектуре на Boosty с ранним доступом. Некоторые темы будут эксклюзивно доступны только на Boosty по подписке. Мы будем читать и обсуждать книгу “Building Micro-Frontends. Scaling Teams and Projects, Empowering Developers”. Книга не переведена на русский язык. В этих видео мы будем обсуждать самую суть книги, без воды. Также я буду давать свои комментарии, основываясь на своем опыте внедрения микрофронтендов в большом проекте.
В этих видео будет дано большое количество полезной информации по всем аспектам распиливания монолита на микрофронтенды. Мы рассмотрим большое количество вариантов внедрения микрофронтенд архитектуры, рассмотрим все достоинства и недостатки вариантов, сложности перехода на микрофронтенд архитектуру и что стоит учесть заранее. Также коснемся принципов Domain Driven Design (DDD) и как эти принципы связаны с микрофронтендами. Рассмотрим следующие темы:
  1. Как распилить монолит на микрофронтенды
  2. Архитектуры фронтенд приложений - SPA, Изоморфные, Статичные, JAMstack
  3. Что такое микрофронтенд и каковы его принципы
  4. Что учитывать при переходе на микрофронтенд
  5. Краткий обзор видов разделения на микрофронтенды
  6. Вертикальное разделение на микрофронтенды
  7. Горизонтальное разделение на микрофронтенды
  8. Микрофронтенд на основе Module Federation
  9. Микрофронтенд на основе iframes
  10. Микрофронтенд на основе веб-компонентов
  11. Server Side микрофронтенды
  12. Edge Side микрофронтенды
  13. Проект с Webpack Module Federation
  14. Эволюция проекта с Webpack Module Federation
  15. Как деплоить микрофронтенды
  16. Как версионировать микрофронтенды
  17. CI/CD микрофронтендов
  18. Стратегии деплоя микрофронтендов
  19. Пример автоматизации пайплайна для микрофронтенда
  20. Общение микрофронтендов с бекендом
  21. Пример распиливания монолита на микрофронтенды. О приложении
  22. Пример распиливания монолита на микрофронтенды. Детали реализации
  23. Как презентовать микрофронтенд архитектуру команде