Уроки45. scan и immutable todo list
Уроки · 45
45. scan и immutable todo list
Immutable updates — закон сохранения старого
В UI-приложениях принято обновлять состояние иммутабельно. Это значит: не менять старые объекты и массивы, а создавать новые. Старый объект должен остаться нетронутым.
Зачем это нужно
- Сравнение по ссылке: Angular OnPush,
distinctUntilChanged, React, Signals — все они проверяют «новое ли это?» через===. Мутация не даст изменения ссылки → UI не обновится. - Time travel: иммутабельные снимки можно сохранять и откатывать.
- Прозрачная отладка: предсказуемо видеть, что изменилось.
Иммутабельные приёмы
// добавить в массив:
[...old, newItem]
// обновить элемент массива по условию:
old.map(item => item.id === id ? { ...item, done: !item.done } : item)
// обновить поле объекта:
{ ...old, name: 'new' }
Что нужно сделать
- Для
action.type === 'add'верните[...todos, { id: action.id, title: action.title, done: false }]. - Для
action.type === 'toggle'вернитеtodos.map(...): для нужногоid— новый объект{ ...todo, done: !todo.done }, иначе самtodo. - В остальных случаях верните
todos. - Никаких
push,splice,todo.done = ...— это мутации!
Решение spoiler · click to reveal
const { from, scan } = Rx;
const actions$ = from([
{ type: 'add', id: 1, title: 'learn RxJS' },
{ type: 'add', id: 2, title: 'build app' },
{ type: 'toggle', id: 1 },
]);
function formatTodos(todos) {
return todos
.map(todo => todo.title + '[' + (todo.done ? 'x' : ' ') + ']')
.join(' | ');
}
const todos$ = actions$.pipe(
scan((todos, action) => {
if (action.type === 'add') {
return [
...todos,
{ id: action.id, title: action.title, done: false },
];
}
if (action.type === 'toggle') {
return todos.map(todo => {
if (todo.id !== action.id) {
return todo;
}
return { ...todo, done: !todo.done };
});
}
return todos;
}, [])
);
todos$.subscribe(todos => console.log('Todos: ' + formatTodos(todos))); script.ts
CONSOLE · Console Output
Нажмите на запуск, чтобы увидеть результат...