Всем привет!
Мне очень нравится «Внедрить что-то с нуля» Тип статьи, например:
- Потерян с redux и сагами? Реализуйте их сами!
- Здание Redux с нуля
- Создайте свои собственные реагирование – Этот особенно потрясающий
Это хороший способ узнать, как все работает, и раскрыть магию за черным ящиком библиотеки.
Я планирую написать маленький Эффектор ☄️. – подобная библиотека под названием Е ~ Wee ~. CTOR Отказ Это будет проект для образовательных целей.
- Название «Eweific» получено из «эффектора» и «Wee», что означает «маленький, маленький, крошечный»
- Второе значение «Wee» также соответствует
- Также меня зовут Виктор, и мне нравится, как звучит «Eweific»:)
Хорошее и простое место для начала – это пример «счетчика» из Эффектор веб-сайт :
import {createStore, createEvent} from 'effector'
const add = createEvent()
const sub = createEvent()
const reset = createEvent()
const counter = createStore(0)
.on(add, (count, n) => count + n)
.on(sub, (count, n) => count - n)
.reset(reset)
counter.watch(n => console.log('counter:', n))
// counter: 0
add.watch(n => console.log('add', n))
sub.watch(n => console.log('subtract', n))
reset.watch(() => console.log('reset counter'))
add(5)
// add 5
// counter: 5
sub(1)
// subtract 1
// counter: 4
reset()
// reset counter
// counter: 0
Таким образом, нам нужно реализовать два основных объекта – событие и магазин – и некоторые из их методов.
Теперь я не буду глубоко погрузиться в эффектор, если вы хотите сделать это, проверьте эту статью. Но вот некоторые основные моменты от архитектуры эффектора:
- Эффектор внутри создает график узлов
- Узлы (очевидно) ссылки на следующий график
- Любой узел может содержать последовательность шагов для запуска
- Шаг может одновременно изменять данные ввода или остановить вычисление отделения или запустить некоторую функцию побочных эффектов
- После некоторого ядра эффектора события проходит входные данные в узле и запускает выполнение шагов, используя Алгоритм поиска по ширину
- Любой высокоуровневый эффектор ( событие , Магазин , Эффект , Домен ) Это какой-то объект, прикрепленный к узлу или кучу узлов.
Вот график логических отношений для кода выше:
И вот какой эффектор создает, структурный граф узлов:
Давайте начнем с основной вещи графа – A Узел Отказ Узел должен содержать ссылки на следующие узлы – края графика и последовательность Шаги – Где мы опишем логику.
export const createNode = ({ next = [], seq = [] } = {}) => ({
next,
seq,
})
CreateNode Заводская функция очень проста, она просто создает объект узла и ничего другого. Мы могли бы даже пойти без него и описать узлы на месте, как простое предметы. Но фабрика функция дает нам два преимущества:
- Каждый и каждый узел, который он возвращается, имеет ту же структуру Итак, мы не будем упустить несколько полей, определяющих их вручную
- Синтаксис ES6 имеет очень удобное Параметры по умолчанию и Разрушение задания , и они могут взять нагрузку на назначение значений поля по умолчанию для узла
Следующее, что нам нужно, это шаги . Существует шесть типов шагов в эффектере, но мы начнем с одного. И мы даже не будем создавать завод для этого:) Давайте просто использовать Функция как шаг. С таким узлы будут содержать последовательность функций для выполнения.
Событие это самый простой эффекторный блок. Это функция, прикрепленная к узлу графа. Единственная цель события как объекта высокого уровня состоит в том, чтобы разместить входные данные в узел и начать цикл вычислений.
export const createEvent = () => {
const event = payload => launch(event, payload)
event.graphite = createNode()
return event
}
CreateeeVent Фабрика создает функцию и прикрепляет узел графа в его графит поле. Создано событие -функция принимает входные данные и выполняет функцию запуск . Это запуск Функция начнет вычислительный цикл, и мы опишем его позже, когда мы пишем ядро.
Как видите, узел, прикрепленный к событию, не имеет никакого Следующий узлы, ни Шаги Отказ
Прежде чем написать ядро, давайте реализуем Смотреть Функциональность.
Смотреть это вспомогательный узел, который запускает побочный эффект. В случае нашего счетчика пример этот побочный эффект – console.log Отказ
export const watch = unit => fn => {
const node = createNode({
seq: [fn],
})
unit.graphite.next.push(node)
}
Смотреть Функция принимает два аргумента (в значении функционального программирования) – единица Чтобы прикрепить Смотреть Узел и функция для выполнения.
Поскольку мы решили использовать простые функции как шаги (на данный момент) – мы просто будем использовать данную функцию побочных эффектов в качестве шага для Смотреть узел.
И после создания Смотреть Узел, мы положили этот узел на Следующий массив для данного устройства.
И теперь давайте добавим .watch Метод нашему событие :
export const createEvent = () => {
const event = payload => launch(event, payload)
event.graphite = createNode()
+ event.watch = watch(event)
return event
}
Таким образом, мы сможем смотреть события:
const event = createEvent() event.watch(data => console.log(data))
И здесь мы идем:) Ядро Отказ Это не так пугающее, как это звучит, правда. Есть две основные части ядра: очереди и Цикл вычислений Отказ
Эффектор использует пять очередей. Начнем с одного:
// contains objects { node, value }
const queue = []
Цикл вычисления пересекает график и выполняет каждый шаг из каждого узла:
const exec = () => {
while (queue.length) {
let { node, value } = queue.shift()
node.seq.forEach(step => (value = step(value)))
node.next.forEach(node => queue.push({ node, value }))
}
}
Простые слова функция Exec Может быть описан как следующие шаги:
- В то время как
очередьне пусто, предпринять элемент из очереди - Выполните каждый шаг из узла, с начальным значением из элемента очередей
- Положите каждый узел из
Следующиймассив в очередь, с новым значением - Перейти к 1.
Еще одна вещь – нам нужна функция запуск Для наших событий:
export const launch = (unit, value) => {
queue.push({ node: unit.graphite, value })
exec()
}
запуск Функция просто ставит Узел и ценность в очередь и запускает вычислительный цикл. Вот и все.
И Последнее, но не менее важное – A магазин Отказ
export const createStore = defaultState => {
let currentState = defaultState
const store = {}
store.graphite = createNode({
seq: [value => (currentState = value)],
})
return store
}
Createstore Фабрика создает объект и прикрепляет узел графа в его графит Поле, как и с событием. Но магазин Узел имеет один шаг – он сохраняет входные данные в прилагаемую переменную Текущее состояние .
Нам также нужно реализовать несколько методов магазина, как .на , .reset и .смотреть . Давайте начнем с последнего:
store.watch = fn => {
fn(currentState)
return watch(store)(fn)
}
.watch Способ для хранения немного отличается, чем для события – впервые его называется, он выполняет заданную функцию с текущим состоянием, а затем создает Смотреть узел.
store.on = (event, fn) => {
const node = createNode({
next: [store.graphite],
seq: [value => fn(currentState, value)],
})
event.graphite.next.push(node)
return store
}
.на Метод принимает событие (или любую единицу) и функцию редуктора. Как .watch метод Это создает новый на Узел, с одним шагом, где вызывается редуктор. И помещает этот новый узел до магазин Узел на графике, поэтому новое значение от редуктора будет сохранено в магазин узел. Также это ставит этот новый узел Следующий массив для данного события (или единицы).
store.reset = event => store.on(event, () => defaultState)
.reset Метод просто ярлык для установки исходного состояния.
И мы сделали первый шаг в этом путешествии. Если мы объединяем все эти части вместе, мы получим минимальный рабочий «эректор», который мог бы запустить счетчик пример. А что важнее – это следует эффектному архитектуре!
В следующих главах мы вырастем наш младенца. Я постараюсь прикрыть все эффекторные API в разумных пределах, поэтому оставаться настроенными;)
Я создал Проект на Github Чтобы помочь вам последовать исходным кодом. Все код, описанный в этой главе, совершено в Это совершает Отказ
Спасибо за чтение!
Оригинал: “https://dev.to/effector/e-wee-ctor-writing-tiny-effector-from-scratch-1-1kap”