sample
Formulae
sample({ source, clock, target, fn? }): target
When clock
is triggered, read the value from source
and trigger target
with it.
- If the
fn
is passed, pass value fromsource
through before passing totarget
- If the
target
is not passed, create it and return fromsample()
target
Type of the created If target
is not passed to sample()
call, it will be created internally. The type of the unit is described in the table below:
clock\source | Store | Event | Effect |
---|---|---|---|
Store | Store | Event | Event |
Event | Event | Event | Event |
Effect | Event | Event | Event |
How to read it:
- You need to know type of the
source
, it is a column - Type of the
clock
in the rows - Match the column and the row
For example:
const $store = sample({ source: $store, clock: $store });// Result will be store, because source and clock are stores.
const event = sample({ source: $store, clock: event });// Because not all arguments are stores.
sample(sourceStore, clockEvent, fn?)
Overall this method can be used for linking two nodes, resulting the third one, which will fire only upon clock
node trigger.
Passes current sourceStore
's state and clockEvent
's value to fn
handler. Quite a common case, when you need to handle some event with some store's state. Instead of using store.getState()
in body of effect, which may cause race conditions and inconsistency of state at the moment of effect's handler invocation, it is more suitable to use sample
method as described below.
Arguments
sourceStore
(Store): Source storeclockEvent
(Event): Clock(Trigger) eventfn
? ((source, clock) => result): Optional combinator function, should be pure. Since, this handler is supposed to organize data flow, you should avoid declaring side-effects here. It's more appropriate to place it inwatch
method for sampled node.
Returns
Event, which fires upon clock trigger
Example 1
import {createStore, createEvent, sample} from 'effector'
const store = createStore('hello zerobias')const event = createEvent()
const sampled = sample(store, event)sampled.watch(console.log)
event() // => hello zerobias
Example 2
import {createStore, createEvent, sample} from 'effector'
const login = createStore('peter')const sendMessage = createEvent()
const fullMessage = sample(login, sendMessage, (login, text) => ({login, text}))
fullMessage.watch(({login, text}) => { console.log(`[${login}]: ${text}`)})
sendMessage('hello')// => [peter]: hellosendMessage('how r u?')// => [peter]: how r u?
sample(sourceEvent, clockEvent, fn?)
Passes last sourceEvent
invocation argument value and clockEvent
value to fn
handler.
Arguments
sourceEvent
(Event): Source eventclockEvent
(Event): Clock(Trigger) eventfn
? ((source, clock) => result): Optional combinator function, should be pure
Returns
Event, which fires upon clock trigger
Example
import {createEvent, sample} from 'effector'
const event1 = createEvent()const event2 = createEvent()
const sampled = sample(event1, event2, (a, b) => `${a} ${b}`)sampled.watch(console.log)
event1('Hello')event2('World') // => Hello Worldevent2('effector!') // => Hello effector!
sampled('Can be invoked too!') // => Can be invoked too!
sample(event, store, fn?)
Passes last event
invocation argument value and store
's updated state to fn
handler.
Note:
event
must be invoked at least once.
Arguments
event
(Event): Source eventstore
(Store): Triggers sampled unit upon store updatefn
? ((source, clock) => result): Optional combinator function, should be pure
Returns
Event, which fires upon clock is triggered
Example
import {createEvent, createStore, sample} from 'effector'
const event = createEvent()const inc = createEvent()const count = createStore(0).on(inc, state => state + 1)
const sampled = sample( event, count, (c, i) => `Current count is ${i}, last event invocation: ${c}`,)sampled.watch(console.log)
inc() // => nothing
event('foo')inc() // => Current count is 2, last event invocation: foo
event('bar')inc() // => Current count is 3, last event invocation: bar
sample(sourceStore, clockStore, fn?)
Passes last sourceStore
's current state and clockStore
's updated state to fn
handler, upon clockStore
's update.
Arguments
sourceStore
(Store): Source storeclockStore
(Store): Triggers sampled unit upon store updatefn
? ((source, clock) => result): Optional combinator function, should be pure
Returns
Store, which updates upon clock update
Example
import {createEvent, createStore, sample} from 'effector'
const inc = createEvent()const setName = createEvent()
const name = createStore('John').on(setName, (_, v) => v)
const clock = createStore(0).on(inc, i => i + 1)
const sampled = sample(name, clock, (name, i) => `${name} has ${i} coins`)sampled.watch(console.log)// => John has 0 coins (initial store update triggered sampled store)
setName('Doe')inc() // => Doe has 1 coins
sample({source, clock?, fn?, greedy?, target?})
Object-like arguments passing, works exactly the same as examples above do.
clock
- trigger node, if not passed, the source
is used as clock
greedy
modifier defines whether sampler will wait for resolving calculation result, and will batch all updates, resulting only one trigger, or will be triggered upon every linked node invocation, e.g. if greedy
is true
, sampler
will fire on trigger of every node, linked to clock, whereas non-greedy sampler(greedy: false)
will fire only upon the last linked node trigger.
target
- can contain Unit, which accepts payload returned by fn
. If target is passed, result will be the target itself. In case if target is not passed, it's created "under the hood" and being returned as result of the function.
Arguments
params
(Object): Configuration object
Returns
(Event|Store) - Unit, which fires/updates upon clock
is trigged
Example 1
import {sample, createStore, createEffect, createEvent} from 'effector'
const $user = createStore({name: 'john', password: 'doe'})
const signInFx = createEffect({handler: console.log})const submitForm = createEvent()
const submitted = sample({ source: $user, clock: submitForm, fn: (user, params) => ({user, params}), target: signInFx,})
console.log(submitted === signInFx) // units are equal
submitForm('foo')
Example 2
import {createEvent, createStore, sample} from 'effector'
const clickButton = createEvent()const closeModal = clickButton.map(() => 'close modal')
const lastEvent = createStore(null) .on(clickButton, (_, data) => data) .on(closeModal, () => 'modal')
lastEvent.updates.watch(data => { // here we need everything //console.log(`sending important analytics event: ${data}`)})
lastEvent.updates.watch(data => { //here we need only final value //console.log(`render <div class="yourstatus">${data}</div>`)})
const analyticReportsEnabled = createStore(false)
const commonSampling = sample({ source: analyticReportsEnabled, clock: merge([clickButton, closeModal]), fn: (isEnabled, data) => ({isEnabled, data}),})
const greedySampling = sample({ source: analyticReportsEnabled, clock: merge([clickButton, closeModal]), fn: (isEnabled, data) => ({isEnabled, data}), greedy: true,})
commonSampling.watch(data => console.log('non greedy update', data))greedySampling.watch(data => console.log('greedy update', data))
clickButton('click A')clickButton('click B')
sample(sourceStore)
Shorthand for sample({ source: sourceStore, clock: sourceStore })
, it can be used to make updates of sourceStore
non-greedy, thus batching updates of sourceStore
.
This is especially useful if we are combining different stores, which results in multiple store switches within single update. sample
ensures it will fire only upon the last state
Arguments
sourceStore
(Store): Source store
Returns
Store - Non-greedy store
Example 1
import {createStore, createEffect, sample, combine} from 'effector'
const data = [{name: 'physics', id: 1}]
const fetchContentFx = createEffect({ handler: () => new Promise(resolve => setTimeout(() => resolve(data), 0)),})
const $lessonIndex = createStore(0)const $allLessons = createStore([]).on( fetchContentFx.doneData, (_, result) => result,)
const $lesson = combine( $lessonIndex, $allLessons, (idx, lessons) => lessons[idx],)
const $modal = combine({ isPending: fetchContentFx.pending, content: $lesson,})
const $batchedModal = sample($modal)
$modal.updates.watch(v => console.log('modal update', v))//=> modal update { isPending: true, content: undefined })//=> modal update { isPending: false, content: undefined })//=> modal update { isPending: false, content: Object })// total 3 updates$batchedModal.updates.watch(v => console.log('batchedModal update', v))//=> batched modal update { isPending: true, content: undefined })//=> batched modal update { isPending: false, content: Object })// total 2 updates
fetchContentFx()
sample({ source })
Objects and arrays of Store in Object of stores
sample
can be called with object of (Store)[Store.md] as source
:
import { createStore, createEvent, sample } from 'effector'const trigger = createEvent()
const a = createStore('A')const b = createStore(1)
// Target has type `Event<{ a: string, b: number }>`const target = sample({ source: { a, b }, clock: trigger,})
target.watch((obj) => { console.log('sampled object', obj) // => {a: 'A', b: 1}})
Array of stores
sample
can be called with array of (Store)[Store.md] as source
:
import { createStore, createEvent, sample } from 'effector'const trigger = createEvent()
const a = createStore('A')const b = createStore(1)
// Target has type `Event<[string, number]>`const target = sample({ source: [a, b], clock: trigger,})
target.watch((obj) => { console.log('sampled array', obj) // => ["A", 1]})
// You can easily destructure arguments to set explicit namestarget.watch(([a, b]) => { console.log('Explicit names', a, b) // => "A" 1})