Solid.js — это высокоэффективный фреймворк для создания пользовательских интерфейсов, основанный на реактивных примитивах. В отличие от других популярных фреймворков, таких как React, Solid.js использует более низкоуровневые подходы для отслеживания зависимостей и обновлений, что позволяет достичь максимальной производительности. Однако для эффективной работы с Solid.js важно понимать, как создавать и использовать собственные реактивные примитивы. Это ключевая часть работы с данным фреймворком, так как реактивность является основой его архитектуры.
В Solid.js реактивность построена на атомах и вычислениях. Атомы представляют собой базовые реактивные значения, а вычисления используются для создания зависимых значений, которые автоматически обновляются при изменении исходных атомов.
Каждый атом в Solid.js — это не просто переменная, а сущность, которая отслеживает свои изменения. Это позволяет Solid.js автоматически обновлять только те части интерфейса, которые зависят от изменившихся данных.
Для создания атомов в Solid.js используется функция
createSignal. Она принимает начальное значение и возвращает
пару: первый элемент — это функция для получения значения, второй —
функция для его обновления.
import { createSignal } from 'solid-js';
const [count, setCount] = createSignal(0);
console.log(count()); // 0
setCount(1);
console.log(count()); // 1
В этом примере создается атом count, который хранит
числовое значение. Функция count() используется для
получения текущего значения, а setCount() — для его
обновления. Это основа для создания реактивных данных в Solid.js.
Чтобы создать зависимость между атомами, можно использовать функцию
createEffect. Этот инструмент позволяет автоматически
отслеживать изменения реактивных данных и выполнять дополнительные
действия.
import { createSignal, createEffect } from 'solid-js';
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log(`Current count: ${count()}`);
});
setCount(1); // Логирует: "Current count: 1"
В данном примере эффект выполняется каждый раз, когда изменяется
значение атома count. При изменении состояния автоматически
выводится новое значение в консоль.
Реактивные примитивы Solid.js можно использовать не только для работы с состоянием, но и для построения более сложных интерфейсов. Например, можно создать компонент, который использует реактивные данные для рендеринга.
import { createSignal } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
return (
<div>
<p>Счёт: {count()}</p>
<button onCl ick={() => setCount(count() + 1)}>Увеличить</button>
</div>
);
}
В этом примере создается простой компонент-счётчик. При каждом клике
на кнопку обновляется значение атома count, и интерфейс
автоматически перерисовывается.
Solid.js позволяет создавать более сложные реактивные примитивы, которые могут служить основой для создания приложений с различными требованиями к производительности и гибкости. Чтобы создать собственные реактивные примитивы, можно комбинировать атомы и эффекты, а также использовать возможности композиции.
Одной из распространённых задач является создание реактивных примитивов для работы с коллекциями данных, такими как массивы или объекты. В Solid.js можно создать такие примитивы, которые будут отслеживать изменения коллекций и автоматически обновлять интерфейс.
import { createSignal } from 'solid-js';
function useList() {
const [list, setList] = createSignal([]);
function addItem(item) {
setList([...list(), item]);
}
return [list, addItem];
}
function ListComponent() {
const [list, addItem] = useList();
return (
<div>
<ul>
{list().map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<button onCl ick={() => addItem('New Item')}>Добавить элемент</button>
</div>
);
}
В данном примере создается собственный реактивный примитив
useList, который оборачивает массив и предоставляет функцию
для его обновления. Этот примитив можно использовать в различных
компонентах для работы с коллекциями данных.
Для более сложных вычислений, зависящих от нескольких атомов, можно
использовать createMemo. Эта функция создает реактивное
вычисление, которое автоматически обновляется, когда изменяются любые из
входных данных.
import { createSignal, createMemo } from 'solid-js';
function PriceCalculator() {
const [price, setPrice] = createSignal(100);
const [taxRate, setTaxRate] = createSignal(0.1);
const totalPrice = createMemo(() => price() * (1 + taxRate()));
return (
<div>
<p>Цена: {price()}</p>
<p>Налог: {taxRate()}</p>
<p>Итоговая цена: {totalPrice()}</p>
<button onCl ick={() => setPrice(price() + 10)}>Увеличить цену</button>
<button onCl ick={() => setTaxRate(taxRate() + 0.05)}>Увеличить налог</button>
</div>
);
}
Здесь используется createMemo для вычисления итоговой
цены, которая зависит от двух атомов: price и
taxRate. Преимущество этого подхода заключается в том, что
итоговая цена будет пересчитываться только тогда, когда одно из значений
изменится.
Для более сложных состояний, которые содержат несколько
взаимосвязанных данных, Solid.js позволяет создавать реактивные
хранилища с помощью createStore. Хранилища являются
коллекциями реактивных данных, и их удобно использовать для более
сложных интерфейсов.
import { createStore } from 'solid-js/store';
function useStore() {
const [state, setState] = createStore({ count: 0, name: 'Solid' });
function increment() {
setState('count', state.count + 1);
}
return { state, increment };
}
function StoreComponent() {
const { state, increment } = useStore();
return (
<div>
<p>Счёт: {state.count}</p>
<p>Название: {state.name}</p>
<button onCl ick={increment}>Увеличить счёт</button>
</div>
);
}
В данном примере используется createStore для создания
хранилища, которое содержит несколько полей: count и
name. Такой подход удобен для работы с состоянием,
состоящим из нескольких взаимосвязанных данных, поскольку изменения в
любом из полей автоматически приводят к обновлению интерфейса.
Создание собственных реактивных примитивов в Solid.js предоставляет гибкость и мощь для разработки сложных пользовательских интерфейсов с высокой производительностью. Используя атомы, вычисления и хранилища, можно эффективно управлять состоянием, делая приложения не только быстрыми, но и легко расширяемыми.