В Svelte stores — это способ управления состоянием,
который позволяет создавать реактивные данные, доступные по всему
приложению. Пользовательские stores представляют собой особый вид store,
который можно настроить и расширить под специфические нужды. В отличие
от стандартных встроенных stores, таких как writable,
readable и derived, пользовательские stores
дают возможность внедрять кастомную логику, а также управлять поведением
хранения данных более гибко.
Store в Svelte — это объект, который хранит данные и уведомляет подписчиков о любых изменениях этих данных. Каждый store в Svelte является подписным объектом. То есть компоненты, подписанные на store, будут автоматически обновляться, когда store изменяет своё состояние.
В Svelte существуют несколько типов встроенных stores:
writable: store, с которым можно как читать, так и
изменять данные.readable: store, с которым только можно читать
данные.derived: store, который зависит от другого store.Пользовательские stores, как правило, реализуются с использованием базовых типов, но предоставляют дополнительные возможности для обработки данных.
Для создания собственного store необходимо реализовать объект, который подписывает подписчиков на изменения состояния и предоставляет методы для управления этим состоянием. Основная задача пользовательского store — обеспечить нужную логику для работы с состоянием, будь то синхронные или асинхронные операции.
import { subscribe, writable } from 'svelte/store';
function createCounter() {
const { subscribe, set, UPDATE } = writable(0);
return {
subscribe,
increment: () => UPDATE(n => n + 1),
decrement: () => UPDATE(n => n - 1),
reset: () => se t(0)
};
}
export const counter = createCounter();
В этом примере создается простой counter store, который использует
базовый writable store. Метод increment
увеличивает счетчик, метод decrement уменьшает его, а метод
reset сбрасывает значение в ноль. Вся логика изменяется с
помощью методов update и set.
Использование writable: Все
пользовательские stores, как правило, начинают с использования
writable store, так как он предоставляет все необходимые
методы для работы с данными: set, update и
subscribe.
Метод subscribe: Это базовая
функция, которая подписывает компонент на изменения данных. Возвращаемый
из store объект subscribe позволяет любому компоненту
подписаться на store и автоматически обновляться при его
изменении.
Методы управления состоянием: Внутри
пользовательского store можно создать любые методы для управления
состоянием. Важно помнить, что любые изменения состояния должны
осуществляться через методы set или update,
так как они обеспечивают реактивность.
Асинхронные операции: Если нужно работать с асинхронными данными (например, с запросами к серверу), пользовательские stores могут быть расширены для работы с промисами или другими асинхронными механизмами.
Пример асинхронного store:
import { writable } from 'svelte/store';
function createAsyncData() {
const { subscribe, se t, UPDATE } = writable({ loading: false, data: null, error: null });
return {
subscribe,
fetchData: async (url) => {
UPDATE(state => ({ ...state, loading: true }));
try {
const response = await fetch(url);
const data = await response.json();
se t({ loading: false, data, error: null });
} catch (err) {
se t({ loading: false, data: null, error: err.message });
}
}
};
}
export const asyncData = createAsyncData();
Этот store загружает данные с сервера, обновляя состояние с помощью
метода set и обрабатывает ошибки с использованием
асинхронной логики.
set,
update, и subscribeset: Метод, который напрямую
устанавливает новое значение в store и уведомляет всех подписчиков о его
изменении.
update: Метод, который позволяет
модифицировать текущее состояние store. Он получает функцию, которая
принимает старое состояние и возвращает новое.
subscribe: Функция, которая
позволяет компонентам подписываться на store и получать уведомления о
его изменениях. При изменении состояния store все подписчики обновляются
автоматически.
Иногда необходимо использовать несколько stores в одном компоненте. Для этого достаточно подписаться на несколько store или использовать их комбинированное значение.
Пример комбинирования нескольких stores с помощью
derived:
import { derived } from 'svelte/store';
import { counter } from './counterStore';
import { asyncData } from './asyncDataStore';
export const combinedState = derived(
[counter, asyncData],
([$counter, $asyncData]) => ({
counter: $counter,
asyncData: $asyncData.data
})
);
Этот код создает новый store, который комбинирует значения из двух других stores, обеспечивая реактивное обновление при изменении любого из них.
Пользовательские stores могут инкапсулировать сложную логику работы с состоянием и абстрагировать её от компонентов. Это позволяет легко управлять состоянием и делать компоненты менее зависимыми от внутренней логики хранения данных.
Например, можно создавать stores, которые управляют состоянием формы:
import { writable } from 'svelte/store';
function createForm() {
const { subscribe, set, UPDATE } = writable({
name: '',
email: ''
});
return {
subscribe,
updateField: (field, value) => update(state => ({ ...state, [field]: value })),
reset: () => se t({ name: '', email: '' })
};
}
export const formStore = createForm();
Этот store управляет состоянием формы, позволяя обновлять отдельные поля или сбрасывать все значения.
Для использования пользовательского store в Svelte необходимо
подписаться на него внутри компонента. Для этого в компонентах
используется директива $, которая позволяет напрямую
привязать данные из store к компоненту.
Пример:
<script>
import { counter } from './counterStore';
</script>
<button on:click={() => $counter.increment()}>Increment</button>
<p>Counter: {$counter}</p>
Здесь $counter автоматически подписывает компонент на
изменения store, а реактивное обновление происходит при каждом изменении
значения.
Пользовательские stores в Svelte — мощный инструмент для управления состоянием с возможностью добавления пользовательской логики. Они позволяют инкапсулировать и абстрагировать логику работы с данными, создавая гибкую архитектуру приложений. Использование кастомных stores помогает поддерживать чистоту кода, улучшает его модульность и позволяет эффективно управлять состоянием в крупных приложениях.