Введение в любой фреймвок начинается с написания одного простого компонента. Чаще всего этим компонентом будет «счетчик нажатий». Это своеобразный «hello world» в мире фронтенд разработки. Именно поэтому я и возьму его за основу данного материала.
Когда-то давно я задался вопросом: можно ли создавать фронтенд также легко как в React, но без ререндера и скрытых слоев для вычисления состояния и обновления DOM, а только лишь с помошью конструкций самого языка JavaScript?
Решение этого вопроса и оттачивание АПИ заняло у меня несколько лет экспериментов, переписывания всего с нуля, понимания самой сущности метода и универсализации подхода.
Поэтому без лишних рассуждений хочу предоставить вам код этого компонента. Далее будут показаны три версии одного и того же копонента.
Версия 1
import { update } from '@fusorjs/dom'; const ClickCounter = (props) => { let state = props.count || 0; const self = ( <button click_e={() => {state++; update(self);}}> Clicked {() => state} times </button> ); return self; };
click_e— устанавливает обработчик событий, а_eпозволяет устанавливать множество полезных параметоров, например:click_e_capture_once, для совместимости с W3C стандартом.
Здесь функция компонента вызывается один раз при его создании, а обновление происходит при клике. Также мы извлекли состояние («lifted state up») из самой библиотеки что позволяет использовать любую стратегию управления состоянием.
Вот как выглядит использование этого компонента:
import { getElement } from '@fusorjs/dom'; const App = () => ( <div> <ClickCounter /> <ClickCounter count={22} /> <ClickCounter count={333} /> </div> ); document.body.append(getElement(<App />));
Далее я подумал что мой компонент выглядит достаточно хорошо, но примерно столько же кода потребуется для его создания и в React, а нельзя ли его сделать более компактным?
Версия 2
Здесь я упрощю установку переменной состояния с помощью возможностей JavaScript по распаковке объектных аргументов функции с заданием значений по умолчанию. А также тем фактом что вторым параметром в функцию обработчика события можно передать указатель на сам объект для которого произошло событие.
const ClickCounter = ({ count = 0 }) => ( <button click_e={(event, self) => {count++; update(self);}}> Clicked {() => count} times </button> );
Вот теперь я был доволен. Теперь получилось гораздо компактнее чем в React. Тем более если добавить useCallback, справедливости ради, так как наша функция компонента выполняется единожды и не пересоздает обработчик события.
Долго-ли коротко-ли но меня осенило…
Версия 3
Ведь у нас есть универсальный синтаксис установки параметров для всех атрибутов компонента, так почему не добавить еще один параметр: update?
const ClickCounter = ({ count = 0 }) => ( <button click_e_update={() => count++}> Clicked {() => count} times </button> );
Теперь получился просто идеальный вариант. Я готов поспорить что ни в каком другом фреймворке не получится сделать более компактный переиспользуемый компонент с состоянием. Если знаете такой, напишите пожалуйста в комментариях.
Вот рабочий пример нашего компонента
Итог
Данное упражнение позволило понять что такие простые компоненты, которые содержат обработчики событий, не нуждаются в реактивных системах управления состоянием, таких как useState/Signals/Redux/Mobx… Для них достаточны обыкновенные переменные.
Вот еще один пример такого компонента:
const UppercaseInput = ({ value = "" }) => ( <input value={() => value.toUpperCase()} input_e_update={(event) => (value = event.target.value)} /> )
В терминах React это называется «managed input» компонент. Его попробовать можно тут в альтернативном стиле (не JSX).
Чтобы сократить потребление ресурсов, нужно использовать реактивные состояния только там где это необходимо. Например когда несколько компонентов в рвзных частях DOM используют одни и теже данные которые нужно менять.
Этого легко можно добиться с помощью установки одного коллбека пропсы mount, что так же просто как использовать useState в React. Вот тут разобран подробный пример.
Также эти ссылки могут быть вам полезны:
Спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/911184/
Добавить комментарий