Все потоки
Поиск
Написать публикацию
Обновить
15
0.1
Альберт Базалеев @supercat1337

Пользователь

Отправить сообщение

Неплохо. Хотел спросить где подписки, потом увидел по ссылке )

С удовольствием посмотрел разбор. Спасибо. Было интересно.

В докладе, вроде как, юзается пример со старой версией effector'а. Говорят, что стало меньше бойлерплейта. А так, оба примера довольно многословны.

Вдруг кому-то интересно как можно было бы переписать этот код. Я, юзая свою библу, код с подобным функционалом реализовал бы так:

Hidden text
import { Store } from "@supercat1337/store";

class PostLoader {
    post_id = 0;
    comments = [];
    status = "This is no data yet";

    async getComments() {
        this.status = "Loading comments...";
        this.comments = [];
        try {
            const url = `posts/${this.post_id}/comments`;
            const base = `https://jsonplaceholder.typicode.com`;
            const req = await fetch(`${base}/${url}`);            
            const data = await req.json();
            this.comments = data;
            this.status = `Post ${this.post_id} has ${data.length} comments`;
        }
        catch (e) {
            this.status = `Error ${e}`;
        }
    }
}

const store = new Store();
const postLoader = store.observeObject(new PostLoader);

// подписки на изменения с помощью дата-функций
store.reaction(()=>{
    return [postLoader.post_id];
}, ()=>{
    store.next(()=>{
        console.log(`Start load the post #` + postLoader.post_id);
        postLoader.getComments();
    });
});

store.autorun(()=>{
    console.log(`status: ` + postLoader.status);
});

store.autorun(()=>{
    console.log(`comments: ` + JSON.stringify(postLoader.comments));
});

postLoader.post_id++;

Можно и без классов. Код, который ближе к реатому:

Hidden text
import { Store } from "@supercat1337/store";

const store = new Store();

const post_id = store.createAtom(0); 
const comments = store.createCollection([]);
const status = store.createAtom("This is no data yet");

async function getComments() {
    status.value = "Loading comments...";
    comments.value = [];
    try {
        const url = `posts/${post_id.value}/comments`;
        const base = `https://jsonplaceholder.typicode.com`;
        const req = await fetch(`${base}/${url}`);            
        const data = await req.json();
        comments.value = data;
        status.value = `Post ${post_id.value} has ${data.length} comments`;
    }
    catch (e) {
        this.status = `Error ${e}`;
    }
}

post_id.subscribe(()=>{
    store.next(()=>{
        console.log(`Start load the post #` + post_id.value);
        getComments();
    });
});

status.subscribe(()=>{
    console.log(`status: ` + status.value);
});

comments.subscribe(()=>{
    console.log(`comments: ` + JSON.stringify(comments.value));
});

post_id.value++;

Да, еще в примерах не хватает автоматической отмены fetch, как минимум. Примеры не боевые какие-то.

Еще можно дополнить то, что "неизвестные через черточку" теги не только валидны в HTML 5, а также отображаются со свойством css display: contents.

И это дает прикольный профит - такие теги можно использовать в качестве тегов-группировщиков, которые не влияют на отображение дочерних элементов. Удобно управлять вставленными в DOM document fragments.

Спасибо за ответ! Удачи в развитии :)

Мне кажется, что ошибаться - это вполне норм. И где бы вы ещё получили такую обратную связь и консультации от разных профи? Если кто-то не ошибается, значит тот не работает.

Даже если комментарии оказываются полезнее статьи, тоже ничего страшного. В этом случае статья становится триггером полезного контента от профи. А ты бы сидели знатоки и молчали.

В общем, удачи в творчестве) Не опускайте руки.

Уточню: получившуюся верстку вы в итоге используете в реакте/вью/иной библиотеке с поддержкой компонентов для последующего переиспользования?

Пиарят хорошо на медиуме и реддите, Ютюбе.

В итоге в каком формате храните компоненты? В основе верстки компонентов вы используете Bootstrap?

просто Ваша либа не умеет в автоматические подписки.

Все давно было предусмотрено. Все умеет. Добавил 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

Давайте я вам помогу лучше.Так будет нагляднее.

Bundle size

  1. mobx (60.8 kB MINIFIED, 17.1 kB MINIFIED + GZIPPED)

  2. Supercat Store (11.5 kB MINIFIED, 3.6 MINIFIED + GZIPPED)

Autorun

  1. mobx

autorun(() => {
  counter1div.innerHTML = `counter 1: ${state.counter1}`;
  counter2div.innerHTML = `counter 2: ${state.counter2}`;
});
  1. 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

  1. mobx

reaction(
  () => [state.counter3],
  () => {
    counter3div.innerHTML = `counter 3: ${state.counter3}`;
  }
);
  1. 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

  1. mobx

(async () => {
  await when(() => state.counter1 >= 3);

  alert('Another cool thing is when');
})();
  1. Supercat Store (четко структуированный код)

С помощью реактивных переменных

const when = store.createComputed(() => {
  return state.counter1 >= 3;
});

when.subscribe(() => {
  alert('Another cool thing is when');
});

Как бы объяснить. Не все что меньше строк - лучше.

Посмотрев на код с использованием Supercat Store, программист, не знакомый с библиотекой, поймет что делает код. С ней легко начать работу даже новичку и потом контролировать что новичок написал.

По поводу использования реактивных переменных, очевидно, что работа с ними безопаснее работы с апи на строках. Цена удобства - 1 строка кода на каждую переменную. При этом объявление атома не является каким-то тяжким трудом. Библиотека типизирована. Редактор кода подскажет методы создания реактивных переменных и работы с ними. Реактивные переменные легко импортировать из других модулей, а также найти их референсы по всему проекту. Плюсов вагон и маленькая тележка.

Еще скажу, что архитектура, построенная с помощью явных подписок на конкретные реактивные переменные - это и есть ключ к написанию корректного кода, в нем невооруженным глазом виден принцип разделения ответственности.

И, самое главное, такой подход за счет атомарности и разделения ответственности дает возможность безопасно масштабировать код.

Можно и через атомы. Нет проблем.

https://stackblitz.com/edit/vitejs-vite-nkjk5v?file=main.js&terminal=dev

А то, что реакции явно указываются, так это хорошо. Это улучшает читаемость кода.

Да, конечно. Другое дело.

Вот мой ответ:

https://stackblitz.com/edit/vitejs-vite-u7mvue?file=main.js&terminal=dev

И кстати, мой код более читабельнее.

А when все-таки компьютед по духу.

Пока в комментариях видел только один пример с MobX, и то, всю красоту работы MobX спрятали во внешнюю функцию observer - адаптер для реакта.

Честно говоря, не понял причем тут обёртка методов и промисов. Оборачивают объекты и строят абстракции над объектами для того, чтобы добавлять функционал.

А что касается тех сигналов, то там пока Stage1. Говорить рано ещё о них.

Конечно, не надо! И когда в следующий раз увидите var, обязательно сообщите это читателям.

Разъясните противопоставление "агностик" и "для реакта нет реализации".

В публикации речь же идет о ядре. А адаптеры для фреймворков - все-таки отдельные проекты. Для реакта потом напишу. Там тоже будет одна функция.

Я знаю эту библиотеку. Но то, что указано выше - это биндинг данных к JSX реакта. Читайте как демонстрация работы внешней функции observer, а не то как библиотека работает с данными.

Если бы пример был более нативный, то тогда было бы интереснее сравнить.

В своем примере вы показали, как MobX прибит к реакту.

Да, все верно.

Информация

В рейтинге
3 875-й
Откуда
Екатеринбург, Свердловская обл., Россия
Зарегистрирован
Активность

Специализация

Фронтенд разработчик, Фулстек разработчик
JavaScript
HTML
CSS
Node.js
PHP
Базы данных