HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>Всем привет!</p>
1 <p>Всем привет!</p>
2 <p>Этой мой первый пост в дневнике, и посвящён он библиотеке Redux.</p>
2 <p>Этой мой первый пост в дневнике, и посвящён он библиотеке Redux.</p>
3 <p>За время моего обучения на Hexlet именно эта библиотека породила кучу вопросов а-ля -'как это работает, почему это так работает ?'. Несколько дней я перечитывал теорию по Redux, но в голове не укладывалось, пока я не написал свою собственную версию Redux.</p>
3 <p>За время моего обучения на Hexlet именно эта библиотека породила кучу вопросов а-ля -'как это работает, почему это так работает ?'. Несколько дней я перечитывал теорию по Redux, но в голове не укладывалось, пока я не написал свою собственную версию Redux.</p>
4 <p>Предлагаю вам вместе со мной написать свою версию библиотеки, просто чтобы разобраться как это работает "под капотом".</p>
4 <p>Предлагаю вам вместе со мной написать свою версию библиотеки, просто чтобы разобраться как это работает "под капотом".</p>
5 <p>В Redux ядром всего является объект store, который возвращает нам функция createStore(). Поэтому давайте начнём с создания этой функции.</p>
5 <p>В Redux ядром всего является объект store, который возвращает нам функция createStore(). Поэтому давайте начнём с создания этой функции.</p>
6 <blockquote><p>Согласно документации createStore принимает первым аргументов функцию reducer, а вторым начальное состояние.</p>
6 <blockquote><p>Согласно документации createStore принимает первым аргументов функцию reducer, а вторым начальное состояние.</p>
7 </blockquote><p>const createStore = (reducer, initialState) =&gt; { let state = reducer(initialState, { type: '__INIT__' }); let subscribers = []; return { dispatch(action) { state = reducer(state, action); subscribers.forEach((cb) =&gt; cb()); }, subscribe(cb) { subscribers = [...subscribers, cb]; }, getState() { return state; }, }; };</p>
7 </blockquote><p>const createStore = (reducer, initialState) =&gt; { let state = reducer(initialState, { type: '__INIT__' }); let subscribers = []; return { dispatch(action) { state = reducer(state, action); subscribers.forEach((cb) =&gt; cb()); }, subscribe(cb) { subscribers = [...subscribers, cb]; }, getState() { return state; }, }; };</p>
8 <blockquote><p>Сначала инициализируем state начальными данными.</p>
8 <blockquote><p>Сначала инициализируем state начальными данными.</p>
9 </blockquote><blockquote><p>let state = reducer(initialState, { type: '__INIT__' });</p>
9 </blockquote><blockquote><p>let state = reducer(initialState, { type: '__INIT__' });</p>
10 </blockquote><blockquote><p>Функцию reducer мы напишем позже, но главное понимать, что функция возвращает измененный или неизменённый state.</p>
10 </blockquote><blockquote><p>Функцию reducer мы напишем позже, но главное понимать, что функция возвращает измененный или неизменённый state.</p>
11 </blockquote><blockquote><p>Функция createStore должна вернуть объект store со следующими методами: dispatch(), subscribe(), getState().</p>
11 </blockquote><blockquote><p>Функция createStore должна вернуть объект store со следующими методами: dispatch(), subscribe(), getState().</p>
12 </blockquote><blockquote><p>getState() просто возвращает текущий state.</p>
12 </blockquote><blockquote><p>getState() просто возвращает текущий state.</p>
13 </blockquote><blockquote><p>subscribe() принимает в качестве аргумента callback-функцию и складывает функцию в массив.</p>
13 </blockquote><blockquote><p>subscribe() принимает в качестве аргумента callback-функцию и складывает функцию в массив.</p>
14 </blockquote><blockquote><p>dispatch() принимает в качестве аргумента объект. Этот объект может иметь внутри любые поля и данные, но в обязательном порядке должен иметь поле type. Например { type: 'ADD' }. Когда вызывается метод dispatch(), то state должен быть изменен через reducer. Reducer - это функция, внутри которой данные меняются, в зависимости от описанной внутри логики. После того, как state был изменен, нам нужно последовательно вызвать все callback-функции, которые были добавлены в массив посредством метода subscribe().</p>
14 </blockquote><blockquote><p>dispatch() принимает в качестве аргумента объект. Этот объект может иметь внутри любые поля и данные, но в обязательном порядке должен иметь поле type. Например { type: 'ADD' }. Когда вызывается метод dispatch(), то state должен быть изменен через reducer. Reducer - это функция, внутри которой данные меняются, в зависимости от описанной внутри логики. После того, как state был изменен, нам нужно последовательно вызвать все callback-функции, которые были добавлены в массив посредством метода subscribe().</p>
15 </blockquote><p>Теперь создаем функцию reducer, которая согласно внутренней логики будет менять состояние.</p>
15 </blockquote><p>Теперь создаем функцию reducer, которая согласно внутренней логики будет менять состояние.</p>
16 <p>const ourReducer = (state, action) =&gt; { switch(action.type) { case 'INC': return state + 1; case 'DEC': return state - 1; default: return state; } };</p>
16 <p>const ourReducer = (state, action) =&gt; { switch(action.type) { case 'INC': return state + 1; case 'DEC': return state - 1; default: return state; } };</p>
17 <blockquote><p>Здесь все должно быть понятно. Функция принимает объект action с полем type. Например { type: 'INC }. В зависимости от значения поля type отрабатывает switch-case конструкция и происходит возврат состояния.</p>
17 <blockquote><p>Здесь все должно быть понятно. Функция принимает объект action с полем type. Например { type: 'INC }. В зависимости от значения поля type отрабатывает switch-case конструкция и происходит возврат состояния.</p>
18 </blockquote><p>Дальше создаем объект store, интерфейсами которого и будем манипулировать.</p>
18 </blockquote><p>Дальше создаем объект store, интерфейсами которого и будем манипулировать.</p>
19 <p>const store = createStore(ourReducer, 0);</p>
19 <p>const store = createStore(ourReducer, 0);</p>
20 <p>Теперь попробуем вызвать методы нашего хранилища store. Для начала мы хотим чтобы при изменении нашего состояния в console автоматически печаталось текущее состояние.</p>
20 <p>Теперь попробуем вызвать методы нашего хранилища store. Для начала мы хотим чтобы при изменении нашего состояния в console автоматически печаталось текущее состояние.</p>
21 <p>store.subscribe(() =&gt; console.log(store.getState()));</p>
21 <p>store.subscribe(() =&gt; console.log(store.getState()));</p>
22 <p>Теперь вернем текущее состояние</p>
22 <p>Теперь вернем текущее состояние</p>
23 <p>store.getState(); // -&gt; вернётся 0, так как это начальное состояние.</p>
23 <p>store.getState(); // -&gt; вернётся 0, так как это начальное состояние.</p>
24 <p>Теперь изменим наше состояние методом dispatch(), который внутри вызывает редьюсер, меняющий состояние, и вызывает последовательно все callback функции из массива subscribers.</p>
24 <p>Теперь изменим наше состояние методом dispatch(), который внутри вызывает редьюсер, меняющий состояние, и вызывает последовательно все callback функции из массива subscribers.</p>
25 <p>store.dispatch({ type: 'INC' }); // -&gt; в консоле будет 1 store.dispatch({ type: 'INC' }); // -&gt; в консоле будет 2 store.dispatch({ type: 'DEC' }); // -&gt; в консоле будет 1</p>
25 <p>store.dispatch({ type: 'INC' }); // -&gt; в консоле будет 1 store.dispatch({ type: 'INC' }); // -&gt; в консоле будет 2 store.dispatch({ type: 'DEC' }); // -&gt; в консоле будет 1</p>
26 <p>Как оказалось, ничего сложного здесь нет. Надеюсь мои эксперименты кому-то помогут быстрее вникнуть в то, как работает библиотека Redux.</p>
26 <p>Как оказалось, ничего сложного здесь нет. Надеюсь мои эксперименты кому-то помогут быстрее вникнуть в то, как работает библиотека Redux.</p>
27 <blockquote><p><em>Ниже представлен полный код для удобства копирования в свой редактор:</em></p>
27 <blockquote><p><em>Ниже представлен полный код для удобства копирования в свой редактор:</em></p>
28 </blockquote><p>const createStore = (reducer, initialState) =&gt; { let state = reducer(initialState, { type: '__INIT__' }); let subscribers = []; return { dispatch(action) { state = reducer(state, action); subscribers.forEach((cb) =&gt; cb()); }, subscribe(cb) { subscribers = [...subscribers, cb]; }, getState() { return state; }, }; }; const ourReducer = (state, action) =&gt; { switch(action.type) { case 'INC': return state + 1; case 'DEC': return state - 1; default: return state; } }; const store = createStore(ourReducer, 0); store.subscribe(() =&gt; console.log(store.getState())); store.getState(); store.dispatch({ type: 'INC' }); store.dispatch({ type: 'INC' }); store.dispatch({ type: 'DEC' });</p>
28 </blockquote><p>const createStore = (reducer, initialState) =&gt; { let state = reducer(initialState, { type: '__INIT__' }); let subscribers = []; return { dispatch(action) { state = reducer(state, action); subscribers.forEach((cb) =&gt; cb()); }, subscribe(cb) { subscribers = [...subscribers, cb]; }, getState() { return state; }, }; }; const ourReducer = (state, action) =&gt; { switch(action.type) { case 'INC': return state + 1; case 'DEC': return state - 1; default: return state; } }; const store = createStore(ourReducer, 0); store.subscribe(() =&gt; console.log(store.getState())); store.getState(); store.dispatch({ type: 'INC' }); store.dispatch({ type: 'INC' }); store.dispatch({ type: 'DEC' });</p>