Перейти к содержанию

Примитивы Solid

На этой странице мы расскажем о том, что необходимо знать для начала работы с примитивами Solid и использования примитивов Solid внутри и вне компонентов.

Примитивы

Для начала давайте разберемся с примитивами Solid. Что такое примитивы? Примитивы - это простейшие элементы, функции или типы данных, имеющиеся в любом языке программирования, фреймворке или библиотеке. В Solid примитивы - это строительные блоки, которые будут отвечать за реактивность в вашем приложении Solid. Вот список примитивов Solid:

Примечание: Примитивы Solid могут использоваться в любой области видимости, они не обязаны использоваться внутри компонента. Компоненты Solid не владеют своим состоянием, поскольку являются лишь функциями настройки, которые после настройки не имеют никакого отношения к системе реактивности.

Мы остановимся на наиболее используемых примитивах: createSignal, createMemo, createEffect и createResource. Для более глубокого понимания всех примитивов, имеющихся в Solid, обратитесь к странице concepts.

createSignal

createSignal - наиболее часто используемый примитив в Solid. Он используется для создания переменной реактивного состояния. Он принимает необязательное начальное значение и возвращает кортеж с функцией getter для получения текущего значения и функцией setter для установки значения. Функция setter используется для обновления значения переменной состояния.

createSignal может использоваться для хранения данных практически любого типа, включая объекты и массивы. Однако в Solid для хранения объектов и массивов целесообразно использовать примитив createStore. Это связано с тем, что createStore оптимизирован для работы со случаями вложенной реактивности. Подробнее об этом в справочном разделе.

1
2
3
import { createSignal } from 'solid-js';

const [count, setCount] = createSignal(0);

Функция createSignal не обязательно должна использоваться внутри компонента. Она может быть использована в любом месте вашего приложения. Будь то в компоненте, функции или даже вне компонента или функции.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { createSignal } from 'solid-js';

const [count, setCount] = createSignal(0);

function increment() {
    setCount(count() + 1);
}

function decrement() {
    setCount(count() - 1);
}

function Counter() {
    return (
        <div>
            <button onClick={decrement}>-</button>
            <span>{count()}</span>
            <button onClick={increment}>+</button>
        </div>
    );
}

В приведенном примере у нас есть переменная состояния count, которая используется для отслеживания текущего счета. Для обновления переменной состояния count используются две функции, increment и decrement. У нас также есть компонент Counter, который использует переменную состояния count для отображения текущего счета.

Как вы заметили, в приведенном примере мы используем createSignal вне компонента. Это совершенно нормально, можно даже импортировать сигнал из другого файла, и он все равно будет вести себя реактивно. Вы можете использовать createSignal в любом месте вашего приложения, поскольку в Solid компоненты не владеют своим состоянием. Таким образом, в Solid встроено управление состоянием, и нет необходимости в Redux или других библиотеках управления состоянием, если только вы не хотите использовать специфические для них возможности.

Аналогом этого хука в React является хук useState. Хук useState используется для создания переменной состояния, локальной для компонента. Это означает, что переменная состояния будет уничтожена при размонтировании компонента. В Solid компоненты не владеют своим состоянием. Это означает, что переменная состояния не будет уничтожена при размонтировании компонента. Это связано с тем, что компоненты Solid - это просто функции настройки, которые после настройки не имеют никакого отношения к системе реактивности.

В Vue аналогом этой функции является функция ref. Функция ref используется для создания переменной состояния, которая является локальной для компонента. Это означает, что переменная состояния будет уничтожена при размонтировании компонента. В Solid компоненты не являются владельцами своего состояния. Это означает, что переменная состояния не будет уничтожена при размонтировании компонента. Это связано с тем, что компоненты Solid - это просто функции настройки, которые после настройки не имеют никакого отношения к системе реактивности.

В Svelte аналогом этого слова является ключевое слово let. Ключевое слово let используется для создания переменной состояния, которая является локальной для компонента. Это означает, что переменная состояния будет уничтожена при размонтировании компонента. В Solid компоненты не являются владельцами своего состояния. Это означает, что переменная состояния не будет уничтожена при размонтировании компонента. Это связано с тем, что компоненты Solid - это просто функции настройки, которые после настройки не имеют никакого отношения к системе реактивности.

createMemo

Функция createMemo используется для создания переменной реактивного состояния, которая является производной от других переменных реактивного состояния. Она принимает функцию, возвращающую значение переменной состояния, и возвращает геттерную функцию для получения текущего значения.

1
2
3
4
5
import { createSignal, createMemo } from 'solid-js';

const [count, setCount] = createSignal(0);

const double = createMemo(() => count() * 2);

В приведенном примере у нас есть переменная состояния count, которая используется для отслеживания текущего счета. У нас также есть переменная состояния double, которая является производной от переменной состояния count. Переменная состояния double является мемоизированной версией переменной состояния count. Это означает, что переменная состояния double будет вычисляться заново только при изменении переменной состояния count.

Приведем небольшой пример использования функции createMemo для создания мемоизированного производного состояния и его использования в компоненте.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { createMemo } from 'solid-js';

const [count, setCount] = createSignal(0);

const double = createMemo(() => count() * 2);

function Counter() {
    return (
        <div>
            <button onClick={() => setCount(count() - 1)}>
                -
            </button>
            <span>This is the base value : {count()}</span>
            <span>
                This is the doubled value : {double()}
            </span>
            <button onClick={() => setCount(count() + 1)}>
                +
            </button>
        </div>
    );
}

В приведенном примере у нас есть переменная состояния count, которая используется для отслеживания текущего счета. У нас также есть переменная состояния double, которая является производной от переменной состояния count. Переменная состояния double является мемоизированной версией переменной состояния count. Это означает, что переменная состояния double будет вычисляться заново только при изменении переменной состояния count.

Под капотом createMemo использует createComputed для создания вычисляемого значения. Подробнее о примитиве createComputed в справочном разделе.

Аналогом этой функции в React является хук useMemo. Хук useMemo используется для создания мемоизированной переменной состояния, которая является производной от других переменных состояния. Это означает, что мемоизированная переменная состояния будет вычисляться заново только при изменении одной из переменных состояния, от которых она образована.

Аналогом этой функции в Vue является функция computed. Функция computed используется для создания мемоизированной переменной состояния, которая является производной от других переменных состояния. Это означает, что мемоизированная переменная состояния будет вычисляться заново только при изменении одной из переменных состояния, от которой она получена.

createEffect

Функция createEffect используется для создания реактивного эффекта. Он принимает функцию, которая будет выполняться при изменении переменных реактивного состояния, используемых в функции.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { createSignal, createEffect } from 'solid-js';

const [count, setCount] = createSignal(0);

createEffect(() => {
    console.log('Count has been updated:', count());
});

function Counter() {
    return (
        <div>
            <button onClick={() => setCount(count() - 1)}>
                -
            </button>
            <span>{count()}</span>
            <button onClick={() => setCount(count() + 1)}>
                +
            </button>
        </div>
    );
}

При каждом изменении состояния count будет выполняться эффект. Это удобно для протоколирования, выполнения вызовов API и т.д. Любой побочный эффект, который необходимо запускать при изменении состояния переменной реактивного состояния, может быть выполнен с помощью createEffect.

Аналогом этого хука в React является хук useEffect. Хук useEffect используется для создания побочного эффекта, который будет выполняться при изменении состояния переменной состояния.

Аналогом этой функции в Vue является функция watch. Функция watch используется для создания побочного эффекта, который будет выполняться при изменении состояния переменной состояния.

В Svelte аналогом этого синтаксиса является синтаксис $:. Синтаксис $: используется для создания побочного эффекта, который будет выполняться при изменении состояния переменной состояния.

createResource

createResource - это простой, но очень полезный примитив, который создает сигнал, отражающий значение асинхронной функции. Он принимает асинхронную функцию, необязательные опции и необязательный исходный сигнал, который будет использоваться для заполнения аргумента асинхронной функции.

Вот краткий пример использования createResource для получения данных из API.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { createResource, Show } from 'solid-js';

async function fetchUser(id) {
    const response = await fetch(
        `https://jsonplaceholder.typicode.com/users/${id}`
    );
    return await response.json();
}

function User({ id }) {
    const [id, setId] = createSignal(1);

    const [user] = createResource(id, fetchUser);

    return (
        <div>
            <Show
                when={!user.loading}
                fallback={<LoadingComponent />}
            >
                <div>Name : {user().name}</div>
                <div>Username : {user().username}</div>
                <div>Email : {user().email}</div>
                <div>Phone : {user().phone}</div>
                <div>Website : {user().website}</div>
            </Show>
        </div>
    );
}

Свойство createResource возвращает довольно интересную информацию, которую можно использовать для реактивного отображения состояния ресурса. Как видно, оно имеет свойство loading, представляющее собой булево значение, которое равно true, если ресурс загружается, и false, если не загружается. У него также есть свойство error, которое представляет собой объект error, если при получении ресурса произошла ошибка. createResource также имеет некоторые опции, которые можно использовать для настройки поведения. Вот их список и краткое описание того, что они делают.

  • initialValue : Начальное значение ресурса. Это полезно, если вы хотите отобразить что-то во время загрузки ресурса.
  • name : Имя ресурса. Это полезно для отладки.
  • deferStream : Булево значение, определяющее, следует ли приложению ждать завершения работы ресурса перед выводом в поток. Обратите внимание, что это полезно только в том случае, если вы используете функцию renderToStream.
  • ssrLoadFrom : Эта функция может использоваться для указания ресурсу, должен ли он загружать свои начальные данные из initialValue или с сервера. Это полезно, если у вас есть какие-то данные на стороне сервера, которые вы хотите присвоить этому ресурсу. Это можно сделать, передав в эту опцию либо 'initial', либо 'server'.
  • storage : Эта опция служит декларативным способом хранения данных ресурса. Это удобно, если вы хотите хранить данные в кэше или что-то в этом роде. Эта опция принимает функцию, которая возвращает кортеж с двумя функциями, аксессором и сеттером типа any. Вот пример использования этой опции.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { createResource } from 'solid-js';

async function fetcherFunc(id: number) {
    const response = await fetch(
        `https://jsonplaceholder.typicode.com/users/${id}`
    );
    return await response.json();
}

const [id, setId] = createSignal<number>(1);
const [data, setData] = createSignal<any>({});

const [user] = createResource(id, fetcherFunc, {
    storage: (init: any) => [data, setData],
});

После того как данные ресурса будут разрешены в приведенном выше коде, они будут автоматически сохранены в сигнале data.

Если вы хотите использовать несколько значений сигналов в рамках одного ресурса, вы можете сделать это, создав производное состояние с помощью примитива createMemo. Возможно, вы зададитесь вопросом, почему я использую примитив createMemo, а не просто создаю стандартное производное состояние. Это потому, что createMemo поможет сохранить реактивность производного состояния, в то время как при создании обычного производного состояния производное состояние не будет обновляться при изменении значения состояния. Вот как это может выглядеть в действии.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { createResource, createMemo } from 'solid-js';

// the fetcher function changed to accept an object
async function fetcherFunc(info: {
    id: number;
    name: string;
}) {
    const response = await fetch(
        `https://jsonplaceholder.typicode.com/users/${info.id}/posts?name=${info.name}`
    );
    return await response.json();
}

const [id, setId] = createSignal<number>(1);
const [name, setName] = createSignal<string>('');

// the derived state made using createMemo
const derivedState = createMemo(() => ({
    id: id(),
    name: name(),
}));

const [posts] = createResource(derivedState, fetcherFunc);

Это простой способ, позволяющий использовать более одного значения сигнала в рамках одного ресурса.

Ссылки

Комментарии