Skip to content

Commit 99c8786

Browse files
l5 l6
1 parent fde0047 commit 99c8786

File tree

14 files changed

+938
-28
lines changed

14 files changed

+938
-28
lines changed
17 KB
Loading
240 KB
Loading
11.1 KB
Loading

lessons/lesson05/lesson.md

Lines changed: 347 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,366 @@ description: "Управление состоянием приложения с
55

66
# Управление состоянием приложения, Redux и работа с actions (исторический контекст)
77

8-
<!-- s -->
8+
<!-- v -->
99

1010
## Цели занятия
1111

12-
Освоить Redux Toolkit.
12+
- Понять проблему управления состоянием и мотивацию централизованного стора
13+
- Разобраться с принципами Redux (единственный источник правды, неизменяемость, чистые редьюсеры)
14+
- Научиться проектировать `state`, `actions`, `reducers`, `store`
15+
- Освоить базовые приёмы Redux Toolkit (слайсы, action creators, reducer'ы)
1316

14-
<!-- s -->
17+
<!-- v -->
1518

1619
## Краткое содержание
1720

18-
- Redux Toolkit
19-
- Состояние
20-
- Actions
21-
- Reducers
21+
- Состояние приложения и паттерны событийного взаимодействия (EventBus)
22+
- Мотивация Redux и его 3 принципа
23+
- Термины: `State`, `Action`, `Action Creator`, `Reducer`, `Store`
24+
- Поток данных Redux и практика (mini-redux)
25+
- Расширения: `middleware`, `combineReducers`
26+
- Redux Toolkit: слайсы, генерация actions и reducers
2227

23-
<!-- s -->
28+
<!-- v -->
2429

2530
## Результат
2631

27-
Мини-приложение, применяющие управление состоянием с использованием Redux Toolkit: создание слайса, actions и reducer'а
32+
Миниприложение с централизованным состоянием: определены `state`, `actions`, `reducers`, настроен `store`; реализованы ключевые сценарии с использованием Redux Toolkit (создание слайса, actions и reducer'а)
2833

29-
<!-- s -->
34+
<!-- v -->
3035

3136
## Компетенции по занятию
3237

3338
- Использование React JS
34-
- Использовать Redux Toolkit
39+
- Проектирование и управление состоянием приложения
40+
- Применение Redux/Redux Toolkit на практике
41+
- Понимание middleware и композиции редьюсеров (`combineReducers`)
42+
43+
<!-- s -->
44+
45+
## Введение и мотивация
46+
47+
### OTUS
48+
49+
## Javascript Basic
50+
51+
<!-- v -->
52+
53+
## Вопросы?
54+
55+
<!-- v -->
56+
57+
Какую задачу решает паттерн `Наблюдатель`?
58+
59+
<!-- v -->
60+
61+
Какое API у `EventEmitter` интерфейса?
62+
63+
<!-- v -->
64+
65+
Какую задачу решает паттерн `Посредник` ?
66+
67+
<!-- v -->
68+
69+
Чем `EventBus` отличается от `EventTarget` ?
70+
71+
<!-- s -->
72+
73+
### Управление состоянием приложения, разработка redux
74+
75+
<!-- s -->
76+
77+
### Сначала разберемся с задачей
78+
79+
<!-- v -->
80+
81+
**Состояние приложения** - набор всех переменных/параметров/свойств, которые определяют внешний вид и поведение приложения в каждый конкретный момент времени.
82+
83+
Например:
84+
85+
- какая страница сейчас открыта
86+
- какой элемент сейчас активен
87+
- что пользователь ввел в поле поиска
88+
89+
<!-- v -->
90+
91+
На уровне кода `состояние` - это совокупность переменных и свойств объектов.
92+
93+
<!-- v -->
94+
95+
Где находится состояние в системе, построенной на основе `EventBus` ?
96+
97+
<img src="./images/EventBus.jpeg" title="Event Bus" />
98+
99+
<!-- v -->
100+
101+
В такой системе состояние оказывается `размазанным` по модулям. Это подходит для приложений, которые являются набором независимых блоков. Но при этом отображение одного модуля, не может использовать данные из другого модуля (т.к. модули друг о друге не знают).
102+
103+
<!-- v -->
104+
105+
Поэтому появилась идея "централизованного хранилища" - единого объекта, который хранит в себе все состояние приложения, и обладает всей информацией, которая влияет на приложение.
106+
107+
<!-- v -->
108+
109+
Самым базовым вариантом реализации является использование глобального объекта и глобальных переменных, которые доступны в любой части приложения.
110+
111+
<!-- v -->
112+
113+
Проблема с таким подходом:
114+
115+
- кто угодно может вносить неконтролируемые изменения
116+
- сложно отследить факт изменения переменных состояния (вспоминаем про обновление представления)
117+
118+
<!-- v -->
119+
120+
### Вопросы?
121+
122+
<!-- s -->
123+
124+
### Redux
125+
126+
<!-- v -->
127+
128+
[Мотивация:](https://rajdee.gitbooks.io/redux-in-russian/content/docs/introduction/Motivation.html)
129+
130+
Redux пытается сделать изменения состояния предсказуемыми, путем введения некоторых ограничений на то, как и когда могут произойти обновления. Эти ограничения отражены в трех принципах Redux.
131+
132+
<!-- v -->
133+
134+
### [Redux - 3 принципа](https://rajdee.gitbooks.io/redux-in-russian/content/docs/introduction/ThreePrinciples.html)
135+
136+
- **Единственный источник правды**
137+
Состояние всего вашего приложения сохранено в дереве объектов внутри одного стора.
138+
- **Состояние только для чтения**
139+
Единственный способ изменить состояние — это применить экшен — объект, который описывает, что случится.
140+
- **Мутации написаны, как чистые функции**
141+
Для определения того, как дерево состояния будет трансформировано экшенами, вы пишете чистые редюсеры.
142+
143+
<!-- v -->
144+
145+
### Вопросы?
146+
147+
<!-- v -->
148+
149+
## Redux - Термины
150+
151+
<!-- v -->
152+
153+
### State
154+
155+
Объект в котором хранятся данные приложения
156+
157+
```ts
158+
interface GameOfLifeState {
159+
field: boolean[][];
160+
isRunning: boolean;
161+
speed: number;
162+
}
163+
```
164+
165+
<!-- v -->
166+
167+
### [Action](https://rajdee.gitbooks.io/redux-in-russian/content/docs/basics/Actions.html)
168+
169+
Объект, который описывает, что происходит в системе
170+
171+
```ts
172+
interface Action<T = any> {
173+
type: T;
174+
payload?: any;
175+
}
176+
```
177+
178+
<!-- v -->
179+
180+
### Action Creator (Генератор событий)
181+
182+
Обычная функция, которая возвращает объект `action`. Нужна чтобы писать меньше кода и делать меньше ошибок.
183+
184+
```ts
185+
function changeCellState(x: number, y: number) {
186+
return {
187+
type: "CHANGE_CELL_STATE",
188+
payload: { x, y },
189+
};
190+
}
191+
```
192+
193+
<!-- v -->
194+
195+
### [Reducer](https://rajdee.gitbooks.io/redux-in-russian/content/docs/basics/Reducers.html)
196+
197+
Функция (чистая), которая возвращает новый state как реакцию на action
198+
199+
```ts
200+
type Reducer<S = any, A extends Action = AnyAction> = (
201+
state: S | undefined,
202+
action: A
203+
) => S;
204+
```
205+
206+
<!-- v -->
207+
208+
### Reducer
209+
210+
```ts
211+
function reducer(state: GameOfLifeState, action): GameOfLifeState {
212+
switch (action.type) {
213+
case "START_GAME": {
214+
return {
215+
...state,
216+
isRunning: true,
217+
};
218+
}
219+
case "STOP_GAME": {
220+
return {
221+
...state,
222+
isRunning: false,
223+
};
224+
}
225+
// ...
226+
default: {
227+
return state;
228+
}
229+
}
230+
}
231+
```
232+
233+
<!-- v -->
234+
235+
### [Store](https://rajdee.gitbooks.io/redux-in-russian/content/docs/basics/Store.html)
236+
237+
Объект, который соединяет эти части вместе:
238+
239+
- содержит состояние приложения (application state);
240+
- предоставляет доступ к состоянию с помощью getState();
241+
- предоставляет возможность обновления состояния с помощью dispatch(action);
242+
- обрабатывает отмену регистрации слушателей с помощью функции, возвращаемой subscribe(listener).
243+
244+
<!-- v -->
245+
246+
<img src="./images/redux-data-flow.png" title="Поток данных в Redux" />
247+
248+
<!-- v -->
249+
250+
### Вопросы?
251+
252+
<!-- s -->
253+
254+
[Практика](https://codesandbox.io/s/github/vvscode/otus--javascript-basic/tree/master/lessons/lesson34/code/reduxBasic)
255+
256+
<!-- v -->
257+
258+
### Вопросы?
259+
260+
<!-- s -->
261+
262+
### Это еще не все
263+
264+
<!-- v -->
265+
266+
### [Middlewares](https://rajdee.gitbooks.io/redux-in-russian/content/docs/advanced/Middleware.html)
267+
268+
Предоставляют стороннюю точку расширения, между отправкой экшена и моментом, когда этот экшен достигает редьюсера. Люди используют Redux-мидлвары для логирования, сообщения об ошибках, общения с асинхронным API, роутинга и т.д.
269+
270+
<!-- v -->
271+
272+
<img src="./images/middlewares.gif" title="Middlewares и поток данных в Redux" />
273+
274+
<!-- v -->
275+
276+
### [combineReducers](https://rajdee.gitbooks.io/redux-in-russian/content/docs/recipes/reducers/UsingCombineReducers.html)
277+
278+
<!-- v -->
279+
280+
```ts
281+
type UsersState = {
282+
name: string;
283+
score: number;
284+
}[];
285+
286+
const defaultUsersState = [];
287+
288+
function usersReducer(
289+
state: UsersState = defaultUsersState,
290+
action: Action
291+
): UsersState {
292+
switch (action.type) {
293+
case "ADD_USER":
294+
return [...state, action.payload];
295+
default:
296+
return state;
297+
}
298+
}
299+
```
300+
301+
<!-- v -->
302+
303+
<!-- eslint-skip -->
304+
305+
```ts
306+
interface State {
307+
users: // ... <- usersReducer
308+
gameField: // ... <- gameFieldReducer
309+
}
310+
```
311+
312+
<!-- v -->
313+
314+
```ts
315+
const reducer = combineReducers({
316+
users: usersReducer,
317+
gameField: gameFieldReducer,
318+
});
319+
```
320+
321+
<!-- v -->
322+
323+
Превращает объект, значения которого являются разными функциями-reducer, в единую функцию reducer. Он будет вызывать каждый дочерний reducer и собирать их результаты
324+
в единый объект состояния, ключи которого соответствуют ключам переданных дочерних reducer.
325+
326+
<!-- v -->
327+
328+
Условно тип можно было бы описать как
329+
330+
```ts
331+
type CombineReducer<ReducersConfig = any, Action = { type: any }> = (config: {
332+
[key in keyof ReducersConfig]: (
333+
state: ReducersConfig[key] | undefined,
334+
action: Action
335+
) => ReducersConfig[key];
336+
}) => (
337+
state:
338+
| {
339+
[key in keyof ReducersConfig]: ReducersConfig[key];
340+
}
341+
| undefined,
342+
action: Action
343+
) => {
344+
[key in keyof ReducersConfig]: ReducersConfig[key];
345+
};
346+
```
347+
348+
<!-- v -->
349+
350+
[Практика](https://codesandbox.io/s/github/vvscode/otus--javascript-basic/tree/master/lessons/lesson34/code/combineReducers)
351+
352+
<!-- v -->
353+
354+
### Вопросы?
355+
356+
<!-- s -->
357+
358+
### [Домашнее задание](https://github.com/vvscode/otus--javascript-basic/blob/master/lessons/lesson34/homework.md)
359+
360+
<!-- s -->
361+
362+
Дополнительные материалы:
363+
364+
- [Изучаем Redux и пишем свой Mini-Redux](https://stepansuvorov.com/blog/2017/05/learn-redux/)
365+
- [Изучаем Redux на примере создания мини-Redux](https://medium.com/devschacht/jakob-lind-learn-redux-by-coding-a-mini-redux-d1a58e830514)
366+
- [Описание концепта Middleware](https://rajdee.gitbooks.io/redux-in-russian/content/docs/advanced/Middleware.html)
367+
368+
<!-- s -->
369+
370+
### Опрос о занятии
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# vanilla-client-side-routing-examples
2+
3+
Created with CodeSandbox

0 commit comments

Comments
 (0)