Skip to main content

Чим Effector відрізняється від Redux?

Effector і Redux - це обидва менеджери стану, але вони побудовані на зовсім різних філософіях. Якщо коротко:

Effector - реактивна, декларативна система; Redux - імперативна, редьюсерна архітектура.

Розберемо по пунктах і з прикладами.


1. Підхід до керування станом

EffectorRedux / RTK
ПарадигмаРеактивнаІмперативна
Як описується логіка"Що залежить від чого" (dataflow)"Що робити, коли сталася подія" (reducers)
ОновленняАвтоматичні за залежностямиРучні через dispatch()
ФілософіяОпиши потік данихОпиши, як reducer змінює store

Effector:

javascript
const increment = createEvent() const $count = createStore(0).on(increment, c => c + 1)

Redux:

javascript
const increment = () => ({ type: 'increment' }) const reducer = (state = 0, action) => action.type === 'increment' ? state + 1 : state

2. Архітектура і принципи

EffectorRedux
СтанДекілька незалежних storeОдин великий store (або slices)
Сайд-ефектиЧерез createEffect() (вбудовано)Через thunk, saga, observable тощо
ПідпискиРеактивні (.watch, .map, sample)Через useSelector() / middleware
ТипізаціяВідмінна інтеграція з TypeScriptКраще з Redux Toolkit, але все одно громіздко
ПродуктивністьМінімальні ререндери, fine-grained реактивністьМоже викликати зайві ререндери
SSRІз коробкиПотрібне ручне керування станом

3. Робота з асинхронністю

Effector вбудовано керує асинхронними ефектами:

javascript
const fetchUserFx = createEffect(async id => { const res = await fetch(`/api/users/${id}`) return res.json() }) fetchUserFx.done.watch(({ result }) => console.log('User', result))

У Redux потрібно вручну писати middleware:

javascript
const fetchUser = id => async dispatch => { dispatch({ type: 'pending' }) const res = await fetch(`/api/users/${id}`) dispatch({ type: 'success', payload: await res.json() }) }

Effector робить це декларативно, без middleware.


4. Гнучкість і масштабування

Effector дозволяє описувати залежності явно:

javascript
sample({ source: $user, clock: updateClicked, fn: (user) => ({ ...user, updated: true }), target: $user, })

У Redux подібний реактивний зв'язок неможливий - потрібно вручну диспатчити ланцюжок дій.

Effector не вимагає глобального стора: ти можеш створити локальний store для будь-якого компонента або модуля. Redux же передбачає єдину централізовану структуру (store -> reducer tree).


5. Продуктивність і підписки

Effector підписує компонент тільки на потрібні дані. При зміні інших store компонент не ререндериться.

Redux, навіть з useSelector, часто викликає зайві ререндери, якщо не використовувати мемоізацію (shallowEqual, reselect тощо).


6. Код і DX (Developer Experience)

Effector:

javascript
const addTodo = createEvent<string>() const $todos = createStore<string[]>([]).on(addTodo, (list, todo) => [...list, todo])

Redux Toolkit:

javascript
const todosSlice = createSlice({ name: 'todos', initialState: [], reducers: { addTodo: (state, action) => { state.push(action.payload) } } })

Effector - менше шаблонного коду, більше декларативності і реактивних зв'язків. Redux Toolkit - більш імперативний, але знайомий розробникам зі старих екосистем.


7. Коли обрати що

СценарійЩо обрати
Маленький застосунокZustand, Jotai, Effector
Великий SPA з бізнес-логікоюEffector
Enterprise / Legacy / знайома командаRedux Toolkit
Потрібен строгий dataflow і реактивністьEffector
Потрібен зрозумілий "по кроках" флоуRedux Toolkit

8. Коротко однією фразою

Effector - це реактивний dataflow-менеджер: описуєш зв'язки, і все оновлюється саме. Redux - це імперативний action-reducer-менеджер: викликаєш дії, все оновлюється вручну.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.