Как мыслить в парадигме Effector
Effector — это не просто «менеджер состояния», а также мощный инструмент для построения логики приложения. Здесь мы рассмотрим рекомендации по написанию кода, а также как стоит мыслить при использовании эффектора.
Как правильно подходить к разработке с Effector?
Чтобы эффективно использовать Effector, важно освоить несколько ключевых принципов.
События — основа всего
Приложение — это поток изменений. Каждое изменение — это событие. Важно понимать, что событие не решает, что делать, оно лишь фиксирует факт произошедшего. Это ключевой момент, который помогает избежать жёстких зависимостей.
- Событие — это просто факт: «что-то произошло».
- События не содержат логику — они только объявляют событие, но не решают, как на него реагировать.
- Один факт может привести к разным последствиям — одно событие может запускать несколько независимых процессов.
Пример:
// Не думайте о реализации сейчас — только объявите фактconst searchInputChanged = createEvent();const buttonClicked = createEvent();
Давайте событиям осмысленные название. Например, если вам надо загрузить данные при каком-то действии, то событие связано с действием, а не реализацией:
❌ const fetchData = createEvent()✅ const appStarted = createEvent()
Бизнес-логика и UI — это разные вещи
Правильный подход к архитектуре — держать бизнес-логику отдельно от интерфейса. Effector позволяет это сделать, сохраняя UI простым, а логику — чистой и переиспользуемой.
- UI только отображает данные.
- Effector управляет состоянием и логикой.
Как это выглядит в реальном приложении?
Возьмём в пример GitHub с кнопками «Watch», «Fork» и «Star». Каждое действие пользователя — это событие:
- Пользователь поставил/убрал звездочку -
repoStarToggled
- Строка поиска по репозиторию изменилась -
repoFileSearchChanged
- Репозиторий был форкнут -
repoForked
Логика строится вокруг событий и реакций на них. UI просто сообщает о действии, а их обработка это уже часть бизнес-логики.
Упрощенный пример логики с кнопкой звездочки:
// событие – факт действияconst repoStarToggled = createEvent();
// эффекты как дополнительная реакция на события// (предположим эффекты возвращают обновленное значение)const starRepoFx = createEffect(() => {});const unstarRepoFx = createEffect(() => {});
// состояние приложенияconst $isRepoStarred = createStore(false);const $repoStarsCount = createStore(0);
// логика переключения звездочкиsample({ clock: repoStarToggled, source: $isRepoStarred, fn: (isRepoStarred) => !isRepoStarred, target: $isRepoStarred,});
// отправка запроса на сервер при переключении звездыsample({ clock: $isRepoStarred, filter: (isRepoStarred) => isRepoStarred, target: starRepoFx,});
sample({ clock: $isRepoStarred, filter: (isRepoStarred) => !isRepoStarred, target: unstarRepoFx,});
// обновляем счетчикsample({ clock: [starRepoFx.doneData, unstarRepoFx.doneData], target: $repoStarsCount,});
import { repoStarToggled, $isRepoStarred, $repoStarsCount } from "./repo.model.ts";
const RepoStarButton = () => { const [onStarToggle, isRepoStarred, repoStarsCount] = useUnit([ repoStarToggled, $isRepoStarred, $repoStarsCount, ]);
return ( <div> <button onClick={onStarToggle}>{isRepoStarred ? "unstar" : "star"}</button> <span>{repoStarsCount}</span> </div> );};
При этом UI не знает что там будет происходить внутри, все за что он отвечает – это вызов событий и отображение данных.
Документация на английском языке - самая актуальная, поскольку её пишет и обновляет команда effector. Перевод документации на другие языки осуществляется сообществом по мере наличия сил и желания.
Помните, что переведенные статьи могут быть неактуальными, поэтому для получения наиболее точной и актуальной информации рекомендуем использовать оригинальную англоязычную версию документации.