/
Блог Хекслета
/
Дневник студента
/

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

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

7 октября 2022 г.

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

Всем привет!

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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, которая согласно внутренней логики будет менять состояние.

1
2
3
4
5
6
7
8
9
10
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, интерфейсами которого и будем манипулировать.

1
const store = createStore(ourReducer, 0);

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

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

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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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' });

Виталий Моржов

4 года назад

1

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845