What does merge() do?
What merge is
merge()combines several events (or streams) into one. It creates a new event that fires every time any of the source events fires.
A metaphor:
"I have several sources of events, but I want to react to them as one."
A simple example
import { createEvent, merge } from 'effector'
const loginClicked = createEvent()
const registerClicked = createEvent()
const authStarted = merge([loginClicked, registerClicked])
authStarted.watch(() => console.log('Starting authorization'))
loginClicked() // -> "Starting authorization"
registerClicked() // -> "Starting authorization"So authStarted fires on any of these events.
2. What merge returns
merge() returns a new event
into which all the events from the array are "fused".
The type of the new event is the union (
union) of the source events' payloads.
3. Example with a payload
const emailLogin = createEvent<{ email: string }>()
const phoneLogin = createEvent<{ phone: string }>()
const login = merge([emailLogin, phoneLogin])
login.watch((data) => console.log('Login:', data))
emailLogin({ email: 'a@b.com' })
// -> { email: 'a@b.com' }
phoneLogin({ phone: '+123456' })
// -> { phone: '+123456' }Effector doesn't lose data - it just combines the streams. The payload is preserved from each source.
4. You can also combine effects
merge() also works with effects (via .doneData, .fail, .finally, etc.):
const loadUserFx = createEffect(...)
const loadPostsFx = createEffect(...)
const dataLoaded = merge([loadUserFx.doneData, loadPostsFx.doneData])
dataLoaded.watch(() => console.log('Something finished loading'))Handy when you need to react to "anything that finished".
5. A common pattern: combining different events of the same kind
For example, if you have several actions that should lead to the same result:
const clickedBuy = createEvent()
const clickedAddToCart = createEvent()
const clickedFavorite = createEvent()
const productInteracted = merge([clickedBuy, clickedAddToCart, clickedFavorite])
productInteracted.watch(() => console.log('The user interacted with the product'))Now it doesn't matter which action exactly, the logic runs the same way.
6. Combining merge with other operators
merge() is often used as the first step before guard() or sample():
const loginClicked = createEvent()
const registerClicked = createEvent()
const authClicked = merge([loginClicked, registerClicked])
guard({
source: authClicked,
filter: $isAuthEnabled,
target: startAuthFx,
})This way you combine all possible ways to trigger one logic flow.
7. Behavior
merge()doesn't change the payload;- doesn't duplicate events, it just combines them;
- you can pass an array of any length;
- it works with any type of event/effect.doneData;
- the result is a new event that you can subscribe to or route further (
forward,sample,guard, etc.).
8. Visually
[eventA] ─┐
├──> [merge] → [target]
[eventB] ─┘Every time eventA or eventB fires, the new combined event fires too.
9. Example from a real application
const openedFromMenu = createEvent()
const openedFromSearch = createEvent()
const openedFromLink = createEvent()
const pageOpened = merge([openedFromMenu, openedFromSearch, openedFromLink])
pageOpened.watch(() => console.log('Page opened'))Now you can conveniently log a single pageOpened event,
instead of three separate watch calls.
10. Typing merge in TypeScript
Effector infers types carefully:
const e1 = createEvent<number>()
const e2 = createEvent<string>()
const merged = merge([e1, e2])
// type of merged: Event<number | string>That is, the payload is combined into a union.
TypeScript correctly knows that merged can carry either a number or a string.
Summary
merge()combines several events (or effects) into one. It creates a new event that fires on any of the source ones, passing their payload "as is".
A formula to remember
merge([A, B, C]) -> D, whereD()is called on everyA(),B(),C().
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.