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

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

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

7 октября 2022 г.
2 минуты
1

Всем привет!

Этой мой первый пост в дневнике, и посвящён он библиотеке 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' });

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

3 года назад

1