Скидки до 20% + 2-ая профессия бесплатно и подарки на 50 000₽

Главная | Все статьи | Дневник студента

Redux для самых маленьких: как создать свою библиотеку

Время чтения статьи ~3 минуты
Статья написана студентом Хекслета. Мнение автора может не совпадать с позицией редакции
Redux для самых маленьких: как создать свою библиотеку главное изображение

Всем привет!

Этой мой первый пост в дневнике, и посвящён он библиотеке Redux.

За время моего обучения на Hexlet именно эта библиотека породила кучу вопросов а-ля -'как это работает, почему это так работает ?'. Несколько дней я перечитывал теорию по Redux, но в голове не укладывалось, пока я не написал свою собственную версию Redux.

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

В Redux ядром всего является объект store, который возвращает нам функция createStore(). Поэтому давайте начнём с создания этой функции.

Согласно документации createStore принимает первым аргументов функцию reducer, а вторым начальное состояние.

const createStore = (reducer, initialState) => {
  let state = reducer(initialState, { type: '__INIT__' });
  let subscribers = [];

  return {
    dispatch(action) {
      state = reducer(state, action);
      subscribers.forEach((cb) => cb());
    },
    subscribe(cb) {
      subscribers = [...subscribers, cb];
    },
    getState() {
      return state;
    },
  };
};

Сначала инициализируем state начальными данными.

let state = reducer(initialState, { type: '__INIT__' });

Функцию reducer мы напишем позже, но главное понимать, что функция возвращает измененный или неизменённый state.

Функция createStore должна вернуть объект store со следующими методами: dispatch(), subscribe(), getState().

getState() просто возвращает текущий state.

subscribe() принимает в качестве аргумента callback-функцию и складывает функцию в массив.

dispatch() принимает в качестве аргумента объект. Этот объект может иметь внутри любые поля и данные, но в обязательном порядке должен иметь поле type. Например { type: 'ADD' }. Когда вызывается метод dispatch(), то state должен быть изменен через reducer. Reducer - это функция, внутри которой данные меняются, в зависимости от описанной внутри логики. После того, как state был изменен, нам нужно последовательно вызвать все callback-функции, которые были добавлены в массив посредством метода subscribe().

Теперь создаем функцию reducer, которая согласно внутренней логики будет менять состояние.

const ourReducer = (state, action) => {
  switch(action.type) {
    case 'INC':
      return state + 1;
    case 'DEC':
      return state - 1;
    default:
      return state;
  }
};

Здесь все должно быть понятно. Функция принимает объект action с полем type. Например { type: 'INC }. В зависимости от значения поля type отрабатывает switch-case конструкция и происходит возврат состояния.

Дальше создаем объект store, интерфейсами которого и будем манипулировать.

const store = createStore(ourReducer, 0);

Теперь попробуем вызвать методы нашего хранилища store. Для начала мы хотим чтобы при изменении нашего состояния в console автоматически печаталось текущее состояние.

store.subscribe(() => console.log(store.getState())); 

Теперь вернем текущее состояние

store.getState(); // -> вернётся 0, так как это начальное состояние.

Теперь изменим наше состояние методом dispatch(), который внутри вызывает редьюсер, меняющий состояние, и вызывает последовательно все callback функции из массива subscribers.

store.dispatch({ type: 'INC' }); // -> в консоле будет 1
store.dispatch({ type: 'INC' }); // -> в консоле будет 2
store.dispatch({ type: 'DEC' }); // -> в консоле будет 1 

Как оказалось, ничего сложного здесь нет. Надеюсь мои эксперименты кому-то помогут быстрее вникнуть в то, как работает библиотека Redux.

Ниже представлен полный код для удобства копирования в свой редактор:

const createStore = (reducer, initialState) => {
  let state = reducer(initialState, { type: '__INIT__' });
  let subscribers = []; 

  return {
    dispatch(action) {
      state = reducer(state, action);
      subscribers.forEach((cb) => cb());
    },
    subscribe(cb) {
      subscribers = [...subscribers, cb];
    },
    getState() {
      return state;
    },
  };
};

const ourReducer = (state, action) => {
  switch(action.type) {
    case 'INC':
      return state + 1;
    case 'DEC':
      return state - 1;
    default:
      return state;
  }
};

const store = createStore(ourReducer, 0);

store.subscribe(() => console.log(store.getState())); 
store.getState(); 
store.dispatch({ type: 'INC' }); 
store.dispatch({ type: 'INC' }); 
store.dispatch({ type: 'DEC' }); 
Аватар пользователя Виталий Моржов
Виталий Моржов 07 октября 2022
1
Похожие статьи
Рекомендуемые программы
профессия
Верстка на HTML5 и CSS3, Программирование на JavaScript в браузере, разработка клиентских приложений используя React
10 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на Python, Разработка веб-приложений и сервисов используя Django, проектирование и реализация REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
Тестирование веб-приложений, чек-листы и тест-кейсы, этапы тестирования, DevTools, Postman, SQL, Git, HTTP/HTTPS, API
4 месяца
с нуля
Старт 26 декабря
профессия
Программирование на Java, Разработка веб-приложений и микросервисов используя Spring Boot, проектирование REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
новый
Google таблицы, SQL, Python, Superset, Tableau, Pandas, визуализация данных, Anaconda, Jupyter Notebook, A/B-тесты, ROI
9 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на PHP, Разработка веб-приложений и сервисов используя Laravel, проектирование и реализация REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на Ruby, Разработка веб-приложений и сервисов используя Rails, проектирование и реализация REST API
5 месяцев
c опытом
Старт 26 декабря
профессия
Программирование на JavaScript в браузере и на сервере (Node.js), разработка бекендов на Fastify и фронтенда на React
16 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на JavaScript, разработка веб-приложений, bff и сервисов используя Fastify, проектирование REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
новый
Git, JavaScript, Playwright, бэкенд-тесты, юнит-тесты, API-тесты, UI-тесты, Github Actions, HTTP/HTTPS, API, Docker, SQL
8 месяцев
c опытом
Старт 26 декабря