SolidJS. Быстрый старт
год назад·7 мин. на чтение
Как быстро начать использовать SolidJS
SolidJS — это легковесная JavaScript библиотека для создания пользовательских интерфейсов. Он предоставляет модель реактивного программирования, которая позволяет разработчикам создавать динамические и эффективные приложения. В этом кратком руководстве мы рассмотрим ключевые понятия и функции SolidJS и узнаем, как начать создавать веб-приложения с использованием SolidJS.
Что такое SolidJS?
SolidJS — это декларативная UI библиотека, которая позволяет разработчикам создавать высокопроизводительные веб-приложения с помощью JavaScript. Он следует принципам реактивного программирования, когда компоненты пользовательского интерфейса реагируют на изменения в данных и автоматически обновляются. SolidJS вдохновлен такими библиотеками, как React и Svelte, но нацелен на предоставление более простой и эффективной модели программирования.Установка SolidJS
Чтобы начать работу с SolidJS, вы можете включить библиотеку в свой проект с помощью менеджера пакетов, такого как npm или yarn. Откройте терминал и выполните следующую команду:После завершения установки вы можете импортировать SolidJS в свой проект:npm install solid-js
import { createSignal } from "solid-js";
Пример Hello World
Давайте начнем с создания простого примера «Hello World» с использованием SolidJS. В этом примере мы отобразим приветственное сообщение на экране.В приведенном выше коде мы определяем функциональный компонент под названиемimport { createSignal, render } from "solid-js"; function App() { const [message, setMessage] = createSignal("Hello, World!"); return ( <div> <h1>{message()}</h1> <button onClick={() => setMessage("Hello, SolidJS!")}> Update Message </button> </div> ); } render(() => <App />, document.getElementById("app"));
App
. Внутри компонента мы используем функцию createSignal
для создания реактивного сигнала, называемого message
. Сигнал message
содержит приветственное сообщение, и мы инициализируем его значением Hello, World!
.
В коде JSX мы можем получить доступ к значению сигнала message
с помощью message()
. Это позволяет пользовательскому интерфейсу реагировать на изменения сигнала и динамически обновляться.
Обработчик событий onClick
кнопки обновляет значение сигнала message
на Hello, SolidJS!
при нажатии. Это изменение запускает повторную визуализацию компонента, и обновленное сообщение отображается на экране.
Наконец, мы используем функцию render
для рендеринга компонента App
и монтируем его к элементу DOM с идентификатором app
.
Компоненты и JSX в SolidJS
В SolidJS компоненты пользовательского интерфейса определяются как функции, возвращающие элементы JSX. JSX — это расширение синтаксиса для JavaScript, которое позволяет писать HTML-подобный код в коде JavaScript. Он обеспечивает краткий и выразительный способ описания структуры и содержимого пользовательского интерфейса. Ниже приведен пример простого компонента, который визуализирует кнопку:import { createSignal } from "solid-js"; function Button(props) { const [count, setCount] = createSignal(0); return ( <button onClick={() => setCount(count() + 1)}> {props.label} ({count()}) </button> ); }
Сигналы и реактивное программирование
Сигналы лежат в основе модели реактивного программирования SolidJS. Они представляют собой реактивные значения, которые можно считывать и обновлять. Сигналы создаются с помощью функцииcreateSignal
, которая возвращает пару значений: текущее значение сигнала и функцию для обновления значения.
Чтобы прочитать текущее значение сигнала, мы вызываем сигнал как функцию:import { createSignal } from "solid-js"; const [count, setCount] = createSignal(0);
Чтобы обновить значение сигнала, вызываем функцию обновления с новым значением:console.log(count()); // Output: 0
Сигналы можно использовать в компонентах для создания динамических пользовательских интерфейсов, которые реагируют на изменения в данных. При обновлении сигнала все компоненты, зависящие от этого сигнала, автоматически перерисовываются.setCount(10); console.log(count()); // Output: 10
Условный рендеринг
SolidJS предоставляет несколько компонентов потока управления для условного рендеринга. КомпонентShow
используется для условной визуализации части представления на основе условия.
В этом примере компонентimport { Show } from 'solid-js'; function App() { // ... return ( <div> <Show when={count() > 0}> <h2>Count is greater than 0</h2> </Show> </div> ); }
<Show>
используется для условной визуализации элемента <h2>
только в том случае, если переменная состояния count
больше 0
. Если условие выполнено, будет визуализирован элемент <h2>
; в противном случае он будет скрыт.
Списки и итерации
SolidJS предоставляет компонент<For>
для итерации массивов и рендеринга списка элементов. Давайте изменим наш компонент App
, чтобы отобразить список элементов на основе массива данных.
В этом примере мы инициализируем переменную реактивного состоянияimport { createSignal } from 'solid-js'; function App() { const [items, setItems] = createSignal([ 'Apple', 'Banana', 'Orange' ]); const addItem = () => { const newItem = prompt('Enter a new item:'); if (newItem) { setItems([...items(), newItem]); } }; const removeItem = (index) => { const updatedItems = items().filter((_, i) => i !== index); setItems(updatedItems); }; return ( <div> <ul> <For each={items()}>{(item, index) => ( <li> {item} <button onClick={() => removeItem(index)}>Remove</button> </li> )}</For> </ul> <button onClick={addItem}>Add Item</button> </div> ); } export default App;
items
помощью массива строк. Компонент <For>
используется для перебора массива items
и отрисовки элемента <li>
для каждого элемента. Мы также предоставляем параметр index
для функции обратного вызова для определения позиции каждого элемента в массиве.
Функция addItem
предлагает пользователю ввести новый элемент и добавляет его в массив items
при подтверждении. Функция removeItem
удаляет элемент из массива items
на основе его индекса.
Рефы (Refs) ссылки в SolidJS
Ссылки позволяют получать доступ к базовым элементам DOM в компонентах SolidJS и взаимодействовать с ними. Вы можете думать о ссылках как о способе получения ссылки на определенный элемент, аналогично использованиюgetElementById
в традиционном JavaScript.
SolidJS предоставляет два способа работы с рефами: с помощью переменной напрямую или с помощью функции обратного вызова.
Ссылка на основе переменной
В приведенном выше коде мы определяем переменнуюimport { createSignal, onMount } from "solid-js"; function App() { let myButton; onMount(() => { console.log(myButton); }); return ( <button ref={myButton}> Click me </button> ); }
myButton
и передаем ее в проп ref
элемента button
. Мы используем функцию onMount
для регистрации переменной myButton
после того, как компонент смонтирован и подключен к DOM.
Получив доступ к переменной myButton
, мы можем выполнять действия или получать информацию об элементе button
.
Ссылка на основе функции обратного вызова
В этом примере мы используем функцию обратного вызова для установкиimport { createSignal } from "solid-js"; function App() { const [myButton, setMyButton] = createSignal(null); const handleButtonClick = () => { console.log(myButton()); }; return ( <div> <button ref={setMyButton} onClick={handleButtonClick}> Click me </button> </div> ); }
ref
. Функция setMyButton
вызывается со ссылкой на элемент, когда компонент визуализируется и подключается к модели DOM. Затем мы можем получить доступ к ссылке на элемент в функции handleButtonClick
.
Стилизация компонента
SolidJS предоставляет различные подходы к стилизации компонентов. Вы можете использовать встроенные (inline) стили, классы CSS или библиотеки CSS-in-JS для стилизации компонентов SolidJS.Встроенные стили (inline)
В приведенном выше примере используется пропfunction App() { const [color, setColor] = createSignal("red"); return ( <div> <button style={`background-color: ${color()}`} onClick={() => setColor("blue")} > Change Color </button> </div> ); }
style
для определения встроенных стилей для элемента button
. Значением свойства style
является строка, содержащая пары CSS свойство-значение. Мы можем динамически обновлять стиль, передавая вычисленное значение в прпо style
.
CSS классы
В этом примере мы условно применяем CSS-классfunction App() { const [isActive, setIsActive] = createSignal(false); return ( <div> <button classList={{ "active": isActive()} } onClick={() => setIsActive(!isActive())} > Toggle Active </button> </div> ); }
active
к элементу button
на основе значения сигнала isActive
. Если isActive
имеет значение true
, применяется класс active
; В противном случае класс не применяется.
Обработка ошибок
Обработка ошибок является важным аспектом любого приложения, и SolidJS предоставляет функции для корректной обработки ошибок. Компонент<ErrorBoundary>
позволяет перехватывать и обрабатывать ошибки, возникающие в его дочерних компонентах.
В этом примере компонентimport { ErrorBoundary } from 'solid-js'; function ErrorComponent() { throw new Error('Something went wrong!'); } function App() { return ( <div> <h1>My App</h1> <ErrorBoundary fallback={<div>Error occurred! Please try again.</div>}> <ErrorComponent /> </ErrorBoundary> </div> ); }
<ErrorBoundary>
является оберткой компонента <ErrorComponent>
. Если в <ErrorComponent>
возникает ошибка, вместо сообщения об ошибке будет отображаться резервное содержимое, предоставленное в <ErrorBoundary>
.
Suspense
SolidJS предоставляет компонентSuspense
и возможности асинхронного рендеринга для обработки состояний загрузки и асинхронной выборки данных.
Компонент Suspense
позволяет обрабатывать состояния загрузки и резервные пользовательские интерфейсы в ожидании разрешения данных. Он работает в сочетании с функцией createEffect
для отслеживания состояния загрузки асинхронных операций.
В приведенном выше коде мы имитируем операцию выборки данных с помощью функцииimport { createEffect, createSignal } from 'solid-js'; function fetchData() { return new Promise(resolve => { setTimeout(() => { resolve('Data loaded!'); }, 2000); }); } function App() { const [data, setData] = createSignal(''); const [loading, setLoading] = createSignal(true); createEffect(async () => { setLoading(true); const result = await fetchData(); setData(result); setLoading(false); }); return ( <div> <Suspense fallback={<div>Loading...</div>}> {loading() ? ( <div>Loading...</div> ) : ( <div>{data()}</div> )} </Suspense> </div> ); }
setTimeout
. Компонент App
использует функцию createEffect
для обработки асинхронной выборки данных и соответствующим образом обновляет сигналы loading
и data
. В компоненте Suspense
мы условно визуализируем состояние загрузки или завершение получения данных на основе значения сигнала loading
.
Порталы
Порталы — это мощная функция SolidJS, которая позволяет отображать компоненты за пределами иерархии DOM их родителя. Это полезно, когда вам нужно отобразить компонент в другом элементе DOM, таком как модальное окно или всплывающая подсказка.В этом примере компонентimport { Portal } from 'solid-js/web'; function Modal() { return ( <Portal mount={document.getElementById('modal-root')}> <div className="modal">Modal Content</div> </Portal> ); }
<Portal>
визуализирует модальное содержимое внутри элемента DOM с modal-root
идентификатора, который находится за пределами иерархии DOM родительского компонента. Это позволяет разделять задачи и отображать компоненты в разных частях HTML-документа.
Контекст
Контекст — это мощная функция в SolidJS, которая позволяет обмениваться данными в дереве компонентов без явной передачи пропсов через каждый уровень. Это полезно, когда у вас есть данные, к которым требуется доступ многим компонентам вашего приложения. Для создания контекста можно использовать функциюcreateContext
:
После создания контекста можно указать значение для этого контекста с помощью компонентаimport { createContext } from "solid-js"; const MyContext = createContext();
Provider
:
Чтобы использовать значение контекста в компоненте, можно использовать хук<MyContext.Provider value={/* значение контекста */}> {/* Компоненты, которым нужен доступ к контексту */} </MyContext.Provider>
useContext
:
Обернув компоненты компонентомimport { useContext } from "solid-js"; const MyComponent = () => { const contextValue = useContext(MyContext); // Используем значение из контекста в компоненте };
Provider
, можно сделать значение контекста доступным для всех дочерних компонентов в дереве компонентов.
Контекст — это мощный инструмент для управления глобальным или общим состоянием в приложении. Это помогает сократить объем prop drilling’а и упрощает передачу данных компонентам, которые в них нуждаются.
Итоги
SolidJS предоставляет простую и эффективную модель программирования для создания современных веб-приложений. Его реактивный характер позволяет автоматически обновлять и эффективно визуализировать компоненты, что делает его мощным выбором для разработки интерактивных пользовательских интерфейсов.Хуки useTransition и useDeferredValue в ReactJS 18
2 года назад·3 мин. на чтение
В React 18, релиз которого произошел в марте 2022, появилось много новых инструментов для написания производительных и отзывчивых приложений. Одним из заметных изменений является механизм рендеринга с новой ключевой концепцией: конкурентный рендеринг (concurrent rendering).
В этой статье повнимательнее рассмотрим два новых хука:
Какое обновление можно считать срочным, а какое обычным?
Хук
До React 18 все обновления состояния помечались как "срочные". Это означает, что все обновления состояния обрабатывались одинаково с одинаковым приоритетом.
С помощью
Когда использовать
Одним из примеров может быть список товаров с параметрами фильтрации.
Когда вы переключаете чекбоксы, чтобы выбрать размер или цвет одежды, вы ожидаете, что чекбоксы сразу же отобразят отмеченное или снятое состояние.
А сам список товаров, которые необходимо обновить согласно фильтрам, может быть отдельным и менее срочным обновлением.
Как использовать
Хук
Когда использовать
С помощью
Как использовать
useTransition()
и useDeferredValue()
.
Эти два хука дают возможность определять приоритет обновления состояния, или, скорее, указывать, является ли обновление менее важным, чем другие, и откладывать его в пользу более срочных.
- Срочные обновления: отражают прямое взаимодействие, такое как набор текста, клики, нажатия и т. д., т.е. то с чем взаимодействует пользователь. Когда вы вводите текст в поле ввода, вы хотите сразу увидеть введенный вами текст. В противном случае UI будет казаться медленным и подлагивать. Поэтому мы хотим сделать такие обновления приоритетным.
- Обычные обновления: переход пользовательского интерфейса из одного вида в другой. Пользователи знают, что представление должно измениться или обновиться (например, когда ожидается ответ на запрос данных). Даже если есть небольшая задержка, это можно рассматривать как ожидаемое поведение, и это не будет восприниматься как медлительность приложения.
Хук useTransition()
и функция startTransition()
До React 18 все обновления состояния помечались как "срочные". Это означает, что все обновления состояния обрабатывались одинаково с одинаковым приоритетом.
С помощью useTransition()
теперь можно пометить некоторые обновления состояния как несрочные.
Когда использовать useTransition()
?
Одним из примеров может быть список товаров с параметрами фильтрации.
Когда вы переключаете чекбоксы, чтобы выбрать размер или цвет одежды, вы ожидаете, что чекбоксы сразу же отобразят отмеченное или снятое состояние.
А сам список товаров, которые необходимо обновить согласно фильтрам, может быть отдельным и менее срочным обновлением.
Как использовать useTransition()
?
function App() { const [isPending, startTransition] = useTransition(); const [searchQuery, setSearchQuery] = useState(''); // запрос данных, который занимает некоторое время const filteredResults = getProducts(searchQuery); function handleQueryChange(event) { startTransition(() => { // оборачивая setSearchQuery() в startTransition(), // мы помечаем эти обновления как менее важные setSearchQuery(event.target.value); }); } return ( <div> <input type="text" onChange={handleQueryChange} /> {isPending && <span>Loading...</span>} <ProductsList results={filteredResults} /> </div> ); }
Хук useDeferredValue()
useDeferredValue()
очень похож на useTransition()
в том, что он позволяет отложить несрочное обновление состояния, но применяется его к части дерева.
Это похоже методы debounce и throttle, которые мы часто используем для отложенных обновлений. React будет работать с такими обновлениями, как только завершатся срочные обновления.
Когда использовать useDeferredValue()
?
С помощью useTransition()
вы сами решаете, когда конкретное обновление состояния может быть помечено как менее срочное. Но иногда такой возможности может и не быть, например, если фрагмент кода находится в сторонней библиотеке.
В таких случаях можно воспользоваться хуком useDeferredValue()
. С помощью useDeferredValue()
вы можете обернуть значение и пометить его изменения как менее важные и, следовательно, отложить повторный рендеринг.
useDeferredValue()
будет возвращать предыдущее значение до тех пор, пока есть более срочные обновления для завершения и отображения дерева с обновленным значением.
Как использовать useDeferredValue()
?
function ProductsList({ results }) { // deferredResults получат обновленные данные // когда завершатся срочные обновления const deferredResults = useDeferredValue(results); return ( <ul> {deferredResults.map((product) => ( <li key={product.id}>{product.title}</li> ))} </ul> ); }