Comments 35
Хотелось бы увидит как оно будет использоваться внутри react
Никак, учитывая, что
Computed всегда будут вычисляться от атомов или коллекций, даже если в коде вы укажете только Computed. На этой библиотеке Excel не построить, пока что.
Нет глубокого отслеживания изменения объектов. Если значение атома - объект, то не забывайте прямо указывать присваивание свойству value нового значения.
Когда уже нативные сигналы привезут в браузеры?
Во-первых, явно нескоро.
Во-вторых, потом опять пойдет волна библиотек, которые будут их оборачивать. Например, будут писать обновление данных одним пакетом и отложенные реакции. И будут думать, как выстраивать порядок выполнения реакций (эффектов).
Никто сейчас в здравом уме не оборачивает нативные Промисы или методы коллекций для массивов.
Более того, многие библиотеки стали выкидывать после перехода нативных методов просто в Stage3, потому что разницы по производительности между полифилом и рандомной библиотекой нет, а у полифила хотя бы не находят каждый год фатального недостатка в API.
Промисы просты как валенок
Если посмотреть на fine-grained Reactivity API Vue, то просто сигналов однозначно мало
Реактивность примитивов, объектов, массивов, глубокая и shallow, scopes
Честно говоря, не понял причем тут обёртка методов и промисов. Оборачивают объекты и строят абстракции над объектами для того, чтобы добавлять функционал.
А что касается тех сигналов, то там пока Stage1. Говорить рано ещё о них.
Непонятно зачем минусуют люди. Исходники есть, можно все глянуть. Комментарии в исходнике вполне себе нормальные. Может из-за позиционирования?
Мне вот иногда нужен простой стейт менеджер на бэке, дак днем с огнем что то простое не сыщешь.
Единственное что бросается в глаза - очень длинные названия методов и многословность.
Имхо сравнивают с mobx и понимают что mobx лучше.
А зачем стейт менеджер на бэке, можно узнать?
Задачи какого типа?
Если честно, то это вообще полная фигня. Просто посмотрите на MobX, он на 3 головы лучше и удобнее. Там все подписки/отписки автоматические, как и должно быть. Из "оверхеда" по коду только makeAutoObservable(this); в конструкторе классов с состоянием и observer() для заворачивая компонентов. Всё.
Просто посмотрите https://stackblitz.com/edit/vitejs-vite-y2qj7g?file=src%2FApp.tsx&terminal=dev
В своем примере вы показали, как MobX прибит к реакту.
Он не прибит к реакту. Посмотрите примеры из самого mobx.
Я знаю эту библиотеку. Но то, что указано выше - это биндинг данных к JSX реакта. Читайте как демонстрация работы внешней функции observer, а не то как библиотека работает с данными.
Если бы пример был более нативный, то тогда было бы интереснее сравнить.
А вас есть пример делающий тоже самое?
В публикации речь же идет о ядре. А адаптеры для фреймворков - все-таки отдельные проекты. Для реакта потом напишу. Там тоже будет одна функция.
Если бы пример был более нативный, то тогда было бы интереснее сравнить.
Вот пожалуйста, самый нативный пример https://stackblitz.com/edit/vitejs-vite-wgaaja?file=src%2Fmain.ts&terminal=dev
Да, конечно. Другое дело.
Вот мой ответ:
https://stackblitz.com/edit/vitejs-vite-u7mvue?file=main.js&terminal=dev
И кстати, мой код более читабельнее.
А when все-таки компьютед по духу.
Вы упростили пример - нету кейса когда необходимо делать реакцию на изменения 2 свойств. судить о читабельности - рано кмк.
Необходимо явно подписываться на изменения свойств - при рефакторинге, изменении требований, etc - легко забыть подписаться на нужное свойство/отписаться от ненужного. Да и не хочется этим заниматься.
В коде используются магические константы - при рефакторинге/наборе можно перепутать.
Можно и через атомы. Нет проблем.
https://stackblitz.com/edit/vitejs-vite-nkjk5v?file=main.js&terminal=dev
А то, что реакции явно указываются, так это хорошо. Это улучшает читаемость кода.
Выделил отдельно код по кейсу с двумя переменными:
mobx
autorun(() => {
counter1div.innerHTML = `counter 1: ${state.counter1}`;
counter2div.innerHTML = `counter 2: ${state.counter2}`;
});
Ваше
counter1div.innerHTML = `counter 1: ${state.counter1}`;
counter2div.innerHTML = `counter 2: ${state.counter2}`;
const counter1 = store.getAtom('counter1');
const counter2 = store.getAtom('counter2');
store.onChangeAny([counter1, counter2], () => {
counter1div.innerHTML = `counter 1: ${state.counter1}`;
counter2div.innerHTML = `counter 2: ${state.counter2}`;
});
Вы правда считаете, что распухание кода в 2 раза, копипаста и boilerplate ведет к увеличение читабельности кода?
Давайте я вам помогу лучше.Так будет нагляднее.
Bundle size
mobx (60.8 kB MINIFIED, 17.1 kB MINIFIED + GZIPPED)
Supercat Store (11.5 kB MINIFIED, 3.6 MINIFIED + GZIPPED)
Autorun
mobx
autorun(() => {
counter1div.innerHTML = `counter 1: ${state.counter1}`;
counter2div.innerHTML = `counter 2: ${state.counter2}`;
});
Supercat Store
Решение через строковый API
function foo() {
counter1div.innerHTML = `counter 1: ${state.counter1}`;
counter2div.innerHTML = `counter 2: ${state.counter2}`;
}
foo();
store.onChangeAny(["counter1", "counter2"], foo);
Решение через реактивные переменные
function foo() {
counter1div.innerHTML = `counter 1: ${state.counter1}`;
counter2div.innerHTML = `counter 2: ${state.counter2}`;
}
foo();
const counter1 = store.getAtom('counter1');
const counter2 = store.getAtom('counter2');
store.onChangeAny([counter1, counter2], foo);
Reaction
mobx
reaction(
() => [state.counter3],
() => {
counter3div.innerHTML = `counter 3: ${state.counter3}`;
}
);
Supercat Store
Решение через строковый API
store.subscribe("counter3", () => {
counter3div.innerHTML = `counter 3: ${state.counter3}`;
});
Решение с помощью реактивных переменных
const counter3 = store.getAtom('counter3');
counter3.subscribe(() => {
counter3div.innerHTML = `counter 3: ${state.counter3}`;
});
When
mobx
(async () => {
await when(() => state.counter1 >= 3);
alert('Another cool thing is when');
})();
Supercat Store (четко структуированный код)
С помощью реактивных переменных
const when = store.createComputed(() => {
return state.counter1 >= 3;
});
when.subscribe(() => {
alert('Another cool thing is when');
});
Как бы объяснить. Не все что меньше строк - лучше.
Посмотрев на код с использованием Supercat Store, программист, не знакомый с библиотекой, поймет что делает код. С ней легко начать работу даже новичку и потом контролировать что новичок написал.
По поводу использования реактивных переменных, очевидно, что работа с ними безопаснее работы с апи на строках. Цена удобства - 1 строка кода на каждую переменную. При этом объявление атома не является каким-то тяжким трудом. Библиотека типизирована. Редактор кода подскажет методы создания реактивных переменных и работы с ними. Реактивные переменные легко импортировать из других модулей, а также найти их референсы по всему проекту. Плюсов вагон и маленькая тележка.
Еще скажу, что архитектура, построенная с помощью явных подписок на конкретные реактивные переменные - это и есть ключ к написанию корректного кода, в нем невооруженным глазом виден принцип разделения ответственности.
И, самое главное, такой подход за счет атомарности и разделения ответственности дает возможность безопасно масштабировать код.
Давайте я вам помогу лучше.Так будет нагляднее.
дак и до этого было все видно. там остальные случаи слишком простые и на них не видно было суть.
Посмотрев на код с использованием Supercat Store, программист, не знакомый с библиотекой, поймет что делает код. С ней легко начать работу даже новичку и потом контролировать что новичок написал.
c mobX еще проще - т.к. там действий меньше. меньше действий => проще понять что происходит.
По поводу использования реактивных переменных, очевидно, что работа с ними безопаснее работы с апи на строках
в mobX работа идет на уровне свойств стора. помогает ide и компилятор, что еще 'более безопаснее'.
Редактор кода подскажет методы создания реактивных переменных и работы с ними.
И наверное подскажет то, что при вызове store.getAtom() передано неправильное имя свойства стора?
Еще скажу, что архитектура, построенная с помощью явных подписок на конкретные реактивные переменные - это и есть ключ к написанию корректного кода, в нем невооруженным глазом виден принцип разделения ответственности.
просто Ваша либа не умеет в автоматические подписки.
просто Ваша либа не умеет в автоматические подписки.
Все давно было предусмотрено. Все умеет. Добавил autorun, when, reaction.
// @ts-check
import { Store } from '@supercat1337/store';
class State {
counter1 = 0;
counter2 = 0;
counter3 = 0;
incr1 = () => {
this.counter1++;
};
incr2 = () => {
this.counter2++;
};
incr3 = () => {
this.counter3++;
};
}
const store = new Store();
const state = store.observeObject(new State());
const counter1div = document.createElement('div');
const counter2div = document.createElement('div');
const counter3div = document.createElement('div');
const btn1 = document.createElement('button');
btn1.innerText = 'inct 1';
btn1.addEventListener('click', state.incr1);
const btn2 = document.createElement('button');
btn2.innerText = 'inct 2';
btn2.addEventListener('click', () => {
state.counter2++;
});
document.body.appendChild(counter1div);
document.body.appendChild(counter2div);
document.body.appendChild(counter3div);
document.body.appendChild(btn1);
document.body.appendChild(btn2);
(async () => {
await store.when(() => state.counter1 >= 3);
alert('Another cool thing is when');
})();
// Trigger when counter1 or counter2 changed
store.autorun(() => {
counter1div.innerHTML = `counter 1: ${state.counter1}`;
counter2div.innerHTML = `counter 2: ${state.counter2}`;
});
// Trigger when counter3 changed (another way)
store.reaction(
() => [state.counter3],
() => {
counter3div.innerHTML = `counter 3: ${state.counter3}`;
}
);
setInterval(state.incr3, 1000);
https://stackblitz.com/edit/vitejs-vite-lygwhz?file=main.js&terminal=dev
Я человек простой - вижу var в js коде, дальше не читаю...
Supercat Store — новый менеджер состояний на JavaScript