JS Знакомство с популярными JS фреймворками - заключение Составляем сводную таблицу особенностей рассмотренных фреймворков. Для сравнения также добавлю примеры кода на обычном JavaScript и Symbiote.js
В этой серии На основе всего (плюс добавлю несколько пунктов от себя), что мы прошли в этой серии статей, попробуем сделать такую таблицу:
Вывод значения переменной в разметке Пример кода Обычный JavaScript element.innerText = variable Alpine.js <span x-text="variable"></span> Vue Options API <span v-text="variable"></span> или <span>{{ variable }}</span> Vue Composition API ☝️ React/Preact <span>{variable}</span> Svelte ☝️ Solid <span>{variable()}</span> Symbiote.js <span>{{variable}}</span>
Вывод переменной с HTML в разметке Пример кода Обычный JavaScript element.innerHTML = variable Alpine.js <span x-html="variable"></span> Vue Options API <span v-html="variable"></span> Vue Composition API ☝️ React/Preact <span dangerouslySetInnerHTML={{ __html: variable }}/> или с помощью сторонней библиотеки типа html-react-parser Svelte <span>{@html variable}</span> Solid <span innerHTML={variable}></span> Symbiote.js <span ${{innerHTML: 'variable'}}></span>
Условия в разметке if if-else Обычный JavaScript Любые условия JS только в скрипте 👈 Alpine.js <template x-if="condition">Видно?</template> <template x-if="condition">Видно?</template><template x-if="!condition">Не видно!</template> Vue Options API <span v-if="condition">Видно?</span> <span v-if="condition">Видно?</span><span v-else>Не видно!</span> Vue Composition API ☝️ ☝️ React/Preact {condition && (<span>Видно?</span>)} {condition ? (<span>Видно?</span>): (<span>Не видно!</span>)} Svelte {#if condition}<span>Видно?</span>{/if} {#if condition}<span>Видно?</span>{:else}<span>Не видно!</span>{/if} Solid <Show when={condition}><span>Видно?</span></Show> <Switch><Match when={condition}>Видно?</Match><Match when={!condition}>Не видно!</Match></Switch> Symbiote.js <span ${{'@hidden': '!condition'}}>Видно?</span> <span ${{'@hidden': '!condition'}}>Видно?</span><span ${{'@hidden': 'condition'}}>Не видно!</span>
Циклы в разметке Пример кода Обычный JavaScript Любые циклы JS только в скрипте Alpine.js <template x-for="(item, index) in items" :key="index"><li x-text="item.text"></li></template> Vue Options API <li v-for="(item, index) in items" :key="index">{{ item.text }}</li> Vue Composition API ☝️ React/Preact {items.map((item, index) => <li key={index}>{item.text}</li>))} Svelte {#each items as item (item.id)}<li>{item.text}</li>{/each} Solid <For each={items()}>{(item, index) => <li>{item.text}</li>}</For> Symbiote.js <ul itemize="items"><li>{{text}}</li></ul>
Привязка событий Пример кода Обычный JavaScript <button onclick="func()"/> или element.addEventListener('click', func(event)) Alpine.js <button x-on:click="func"/> или <button @click="func"/> Vue Options API <button v-on:click="func"/> или <button @click="func"/> Vue Composition API ☝️ React/Preact <button onClick={func}/> Svelte <button onclick={func}/> Solid <button onClick={func}/> Symbiote.js <button ${{onclick: 'func'}}/>
Привязка к HTML-элементу Пример кода Обычный JavaScript Инициализация: const element = document.querySelector(selector), использование : element Alpine.js HTML: <input x-ref="anyName"/>, использование: this.$refs.anyName Vue Options API HTML: <input ref="anyName"/>, использование: ☝️ Vue Composition API HTML: ☝️, инициализация: const anyName = ref(null), использование: anyName.value React/Preact HTML: <input ref={anyName}/>, инициализация: const anyName = useRef(), использование: anyName.current Svelte HTML: <input bind:this={anyName}/>, инициализация: let anyName = $state(), использование: anyName Solid HTML: <input ref={anyName}/>, инициализация: let anyName, использование: anyName Symbiote.js HTML: <input ref="anyName"/>, использование: this.ref.anyName
Привязка к значению элемента Пример кода Обычный JavaScript element.addEventListener('input', func(event) {}), использование: event.target.value Alpine.js HTML: <input x-model="anyName"/>, использование: this.anyName Vue Options API HTML: <input v-model="anyName"/>, использование: ☝️ Vue Composition API HTML: ☝️, использование: anyName.value React/Preact HTML: <input ref={anyName}/>, использование: anyName.current.value Svelte HTML: <input bind:value={anyName}/>, использование: anyName Solid HTML: <input value={anyName()} onInput={(e) => setAnyName(e.target.value)} />, использование: anyName Symbiote.js HTML: <input ${{value: 'anyName'}}>
Выполнение кода при загрузке страницы Пример кода Обычный JavaScript window.onload = func Alpine.js Через атрибут x-init="func()" Vue Options API mounted() {func() {// тело функции}, func2() {// тело функции}, ...} Vue Composition API onMounted(func) React/Preact useEffect(() => func, []), useMount(() => func)useSignalEffect(() => func) Svelte onMount(func) Solid onMount(() => func) Symbiote.js initCallback() { func() }
Хранение и изменение состояния Пример кода Обычный JavaScript let someVar = initialValue / someVar = newValue Alpine.js HTML: x-data="{ someVar: initialValue }", использование: this.someVar = newValue Vue Options API data() { return { someVar: initialValue } } / this.someVar = newValue Vue Composition API const someVar = ref(initialValue) / someVar.value = newValue React/Preact const [someVar, setSomeVar] = useState(initialValue) / setSomeVar(newValue)const someVar = useSignal(initialValue) / someVar.value = newValue Svelte let someVar = $state(initialValue) / someVar = newValue Solid const [someVar, setSomeVar] = createSignal(initialValue) / setSomeVar(newValue)const [someVar, setSomeVar] = createStore(initialValue) / setSomeVar(newValue) Symbiote.js init$ = { someVar: initialValue } / this.$.someVar = newValue
Передача состояния между компонентами Как? Обычный JavaScript Через объект window Alpine.js Через события ($dispatch ) или $store Vue Options API provide / inject, Vuex, Pinia Vue Composition API ☝️ React/Preact createContext / useContext, Redux Toolkit , MobX , Valtio , Zustand Svelte svelte/store Solid createContext / useContext Symbiote.js Через пропсы, контексты данных и события
Асинхронные запросы Допустим, нам нужно подгружать данные с API при загрузке страницы. Как можно вызвать асинхронную функцию?
Как? Обычный JavaScript window.onload = func Alpine.js x-init="func()", $watch, x-effect Vue Options API mounted() { func() }, defineAsyncComponent Vue Composition API onMounted(async () => {}), defineAsyncComponent , useFetch , useAxios , useFetch / Composables React/Preact useEffect, useRequest , useAsyncEffect ,useAsync , useQuery , use Svelte onMount(async () => {}), $effect(() => {(async () => {})()}) Solid onMount(async () => {}), createResource Symbiote.js initCallback() {async () => { await func() }}
Сравнение размеров билдов Кроме того, собрав билды всех вариаций нашего проекта TODO (npm run build), можно отсортировать участников сравнения по размерам полученных папок dist и сгенерированных файлов dist/assets/index-*.js:
Разумеется, эти данные относятся всего лишь к нашему демонстрационному проекту, и ваше приложение может оказаться как меньшего, так и гораздо большего размера. С каждым обновлением того или иного фреймворка или библиотеки всё может меняться.
Для обучающихся Попробуйте заменить стили Tailwind в изученных проектах на Bootstrap или Material UI. Или реализуйте отправку POST/PATCH/DELETE запросов на сервер, в зависимости от действий с задачами. Или настройте хранение и обновление задач в localStorage. Это прокачает вас быстрее, чем простое копирование готовых решений.
Документация на русском языке Заключение Не забывайте, что в основе всех рассмотренных нами библиотек и фреймворков лежит обычный JavaScript. Поэтому, если вы этого не сделали ранее, смело открывайте и изучайте — главу за главой, абзац за абзацем. Пригодится.
Что вам больше нравится, с тем и работайте. Никто вам ничего не навязывает. Цель данного цикла статей лишь в структурировании информациии и сравнении реализаций одного и того же проекта с помощью разных инструментов. Ведь каждый фреймворк — всего лишь инструмент, а инструменты применяются в зависимости от конкретной задачи.