Создание собственных реактивных примитивов

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 предоставляет гибкость и мощь для разработки сложных пользовательских интерфейсов с высокой производительностью. Используя атомы, вычисления и хранилища, можно эффективно управлять состоянием, делая приложения не только быстрыми, но и легко расширяемыми.