Що робить sample() в Effector?
1. Що таке sample
sample() - це механізм реактивного зв'язування даних між джерелом (
source) і «тригером» (clock). Коли відбувається подія (clock), sample «бере» поточне значення (source) і передає його далі - уtargetабоfn.
Тобто sample = «Коли відбулося це, візьми те і зроби те-то».
2. Базовий приклад
import { createEvent, createStore, sample } from 'effector'
const nameChanged = createEvent<string>()
const submitClicked = createEvent()
const $name = createStore('')
$name.on(nameChanged, (_, value) => value)
sample({
source: $name,
clock: submitClicked,
fn: (name) => `Submitting the form with name: ${name}`,
target: console.log,
})
nameChanged('Alex')
submitClicked()
// => "Submitting the form with name: Alex"Пояснення:
- clock (тригер) = submitClicked
- source (дані) = $name
- при кліку submitClicked береться поточне $name
- fn() створює результат, який іде в target
3. Мнемоніка:
sample = «clock відбувся -> взяти snapshot із source»
4. Параметри sample
sample({
source, // where we get data from
clock, // when we do this
fn, // how we transform it
filter, // (optional) when it's allowed to pass through
target, // where the result goes (event, effect, store)
})Приклад із filter:
sample({
source: $form,
clock: submitClicked,
filter: $formValid,
target: sendFormFx,
})Відправимо форму (sendFormFx) лише якщо $formValid === true.
5. Приклад зв'язку кількох джерел
source може бути не лише одним store, а об'єктом із кількох сторів:
sample({
source: { name: $name, email: $email },
clock: submitClicked,
fn: ({ name, email }) => ({ name, email }),
target: sendFormFx,
})Тепер sample візьме одразу значення обох сторів у момент кліку.
6. Візуально (потік даних)
[source] ---\
> sample() ---> [target]
[clock] ----/- source -> звідки беремо дані
- clock -> що тригерить «взяття семпла»
- target -> куди йде результат
7. Чому sample кращий за .watch() або .on()
| .watch() | .on() | sample() | |
|---|---|---|---|
| Реагує на зміну? | Завжди | Завжди | Лише за clock |
| Контролює момент часу | Ні | Ні | Так |
| Дозволяє фільтрувати та зв'язувати | Ні | Ні | Так |
| Використовується для реактивних потоків | Частково | Ні | Основний інструмент |
Приклад:
sample({
source: $user,
clock: logoutClicked,
fn: () => null,
target: $user,
})При кліку на logout - обнуляємо $user. .on() тут не підійшов би, адже це не просто зміна стору, а дія за подією.
8. Реальний приклад із застосунку
const loginClicked = createEvent()
const $credentials = createStore({ email: '', password: '' })
const loginFx = createEffect(async (creds) => api.login(creds))
sample({
clock: loginClicked,
source: $credentials,
filter: $isFormValid,
target: loginFx,
})Тепер усе реактивно:
- при кліку на «Login»
- якщо форма валідна
- надсилаємо $credentials у loginFx.
Без зайвого useEffect, if, setState - чиста реактивна логіка.
9. Комбінування sample
Можна викликати sample() ланцюжком - будувати графи залежностей:
const submitClicked = createEvent()
const $data = createStore({ name: 'Alex' })
const saveFx = createEffect(api.saveUser)
const saved = sample({ clock: submitClicked, source: $data, target: saveFx })
sample({
clock: saveFx.doneData,
fn: () => 'Saved successfully!',
target: console.log,
})10. Частий патерн: sample замість "if/await/useEffect"
Філософія Effector:
«Жодних if (formValid) sendForm() - усе описується реактивно через sample і filter».
Це дозволяє писати чисту, детерміновану бізнес-логіку, де порядок дій завжди передбачуваний.
ПІДСУМОК
sample() - це фундамент Effector для реактивних зв'язків: коли відбувається одна подія (clock), бібліотека бере актуальні дані з source, опційно фільтрує/трансформує їх, і надсилає результат у target.
Формула запам'ятовування:
clock відбувся -> «семплюємо» source -> fn() -> target.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.