Sample

sample(sourceStore, clockEvent, fn?)

Overall this method can be used in order to link 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 appropriate to use sample method as described below.

Returned Unit may be observed (via watch), since it's valid graph node.

Arguments

  1. sourceStore (Store): Source store
  2. clockEvent (Event): Clock(Trigger) event
  3. fn? ((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 in watch method for sampled node.

Returns

(Event) - Event, which fires upon clock is triggered

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

Try it

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]: hello
sendMessage('how r u?')
// => [peter]: how r u?

Try it

sample(sourceEvent, clockEvent, fn?)

Passes last sourceEvent invocation argument value and clockEvent value to fn handler.

Arguments

  1. sourceEvent (Event): Source event
  2. clockEvent (Event): Clock(Trigger) event
  3. fn? ((source, clock) => result): Optional combinator function, should be pure

Returns

(Event) - Event, which fires upon clock is triggered

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 World
event2('effector!') // => Hello effector!
sampled('Can be invoked too!') // => Can be invoked too!

Try it

sample(event, store, fn?)

Passes last event invocation argument value and store's updated state to fn handler.

Arguments

  1. event (Event): Source event
  2. store (Store): Triggers sampled unit upon store update
  3. fn? ((source, clock) => result): Optional combinator function, should be pure

Returns

(Event) - 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

Try it

sample(sourceStore, clockStore, fn?)

Passes last sourceStore's current state and clockStore's updated state to fn handler, upon clockStore's update.

Arguments

  1. sourceStore (Store): Source store
  2. clockStore (Store): Triggers sampled unit upon store update
  3. fn? ((source, clock) => result): Optional combinator function, should be pure

Returns

(Store) - 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

Try it

sample({source, clock, fn, greedy?, target?})

Object-like arguments passing, working exactly the same as examples above do.

greedy modifier defines, whether sampler will wait of resolving calculation result, and will batch all updates, resulting only one trigger, either will be triggered upon every linked node invocation, e.g. if greedy is true, sampler will fire, upon trigger of every node, linked to clock, whereas non-greedy sampler(greedy: false) will fire upon the last linked node trigger.

target - can contain Unit, which accepts payload - returned by fn. If target passed, result will be the target itself. In case, target not passed, it's created "under the hood" and being returned as result of the function.

Arguments

  1. 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 signIn = createEffect({handler: console.log})
const submitForm = createEvent()
const submitted = sample({
source: $user,
clock: submitForm,
fn: (user, params) => ({user, params}),
target: signIn,
})
console.log(submitted === signIn) // units are equal
submitForm('foo')

Try it

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')

Try it

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, and resulting store switches its state multiple times within single update. sample ensures it will fire only upon the last state

Arguments

  1. 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 fetchContent = createEffect({
handler: () => new Promise(resolve => setTimeout(() => resolve(data), 0)),
})
const $lessonIndex = createStore(0)
const $allLessons = createStore([]).on(
fetchContent.done,
(_, {result}) => result,
)
const $lesson = combine(
$lessonIndex,
$allLessons,
(idx, lessons) => lessons[idx],
)
const $modal = combine({
isPending: fetchContent.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
fetchContent()

Try it

Objects and arrays with stores in sample source

import {createStore, createEvent, sample, combine} from 'effector'
const trigger = createEvent()
const objectTarget = createEvent()
const arrayTarget = createEvent()
const a = createStore('A')
const b = createStore('B')
sample({
source: {a, b},
clock: trigger,
target: objectTarget,
})
sample({
source: [a, b],
clock: trigger,
target: arrayTarget,
})
objectTarget.watch(obj => {
console.log('sampled object', obj)
// => {a: 'A', b: 'B'}
})
arrayTarget.watch(array => {
console.log('sampled array', array)
// => ['A', 'B']
})
trigger()
/* old way to do this: */
sample({
source: combine({a, b}),
clock: trigger,
target: objectTarget,
})
sample({
source: combine([a, b]),
clock: trigger,
target: arrayTarget,
})

Try it