ФронтендJavaScriptTypeScriptHTML / CSS

SvelteKit 3 для новичка: делаем трекер привычек с нуля

Собираем трекер привычек на SvelteKit 3: форма добавления, реактивный список, сохранение в localStorage и прогресс без лишнего состояния.

Кодик

Автор

6 мин чтения

SvelteKit 3 можно освоить на одном небольшом проекте, если сразу видеть вход, действие и результат. Трекер привычек показывает базовые части SvelteKit на видимом сценарии: форма создаёт запись, кнопка меняет состояние, а прогресс пересчитывается автоматически. Ниже вы соберёте работающий пример и проверите обычный и граничный сценарии.

В первом фреймворк-проекте легко утонуть в маршрутах и серверных API, не успев понять реактивность компонента. Поэтому отделим настройку, входные данные, основное действие и проверку. В этой статье вы соберёте одностраничный трекер с добавлением привычки, отметкой выполнения и восстановлением данных после перезагрузки. Проверка: новая привычка появляется без перезагрузки, прогресс меняется после клика, а localStorage возвращает список при повторном открытии.

1Соберите минимум

создать SvelteKit-приложение и открыть маршрут /. Не расширяйте проект до первого успешного запуска.

2Увидьте данные

добавление обновляет список сразу. Проверяйте значение, а не отсутствие ошибки.

3Измените правило

После успеха добавьте серию дней и отдельный фильтр «только невыполненные». Так копирование станет практикой.

Как устроен учебный проект SvelteKit 3

Страница хранит массив привычек, производное значение считает выполненные элементы, effect синхронизирует данные с localStorage, а шаблон отображает состояние. Держите ввод, логику и отображение раздельно: тогда каждый этап можно проверить отдельно.

ЭтапДействиеПроверяемый результат
Проектсоздать SvelteKit-приложение и открыть маршрут /страница загружается без ошибок
Состояниеописать массив привычек через $stateдобавление обновляет список сразу
Производноепосчитать completed через $derivedсчётчик меняется после отметки
Хранениечитать и записывать localStorage только в браузереперезагрузка восстанавливает данные

Контрольные точки: проект, состояние, производное и хранение. Следующий шаг начинается после совпадения с ожидаемым результатом.

Путь данных в проекте SvelteKit 3
От входных данных до видимого результата. Сначала проверяется вход, затем действие и только потом интерфейс.

Зафиксируйте первый успех Сначала сделайте две привычки прямо в массиве и проверьте реактивную отметку. Подключайте localStorage после работающего интерфейса. Сохраните команду запуска и ожидаемый вывод.

Собираем рабочий пример шаг за шагом

Пример сверялся с актуальной документацией официальному релизу SvelteKit 3 на 19 октября 2026 года. Создайте проект командой npx sv create habits, выберите TypeScript и минимальный шаблон, затем выполните npm run dev. Проверьте текущую папку через pwd или Get-Location. Вставьте пример целиком, выполните один раз, затем разбирайте по частям.

<script lang="ts">
  import { browser } from '$app/environment'

  type Habit = { id: number; title: string; done: boolean }
  let title = $state('')
  let habits = $state<Habit[]>(browser ? JSON.parse(localStorage.getItem('habits') ?? '[]') : [])
  let completed = $derived(habits.filter((habit) => habit.done).length)

  $effect(() => {
    if (browser) localStorage.setItem('habits', JSON.stringify(habits))
  })

  function addHabit() {
    const clean = title.trim()
    if (!clean) return
    habits.push({ id: Date.now(), title: clean, done: false })
    title = ''
  }
</script>

<h1>Привычки: {completed}/{habits.length}</h1>
<form onsubmit={(event) => { event.preventDefault(); addHabit() }}>
  <input bind:value={title} placeholder="Например, 20 минут кода" />
  <button>Добавить</button>
</form>
{#each habits as habit (habit.id)}
  <label><input type="checkbox" bind:checked={habit.done} /> {habit.title}</label>
{/each}
Что должно произойти после запуска
  • Форма добавляет непустую привычку и сразу очищает поле.
  • Счётчик completed/total меняется после отметки без ручного обновления DOM.
  • Повторный запуск даёт тот же предсказуемый результат.
  • Пустой ввод получает понятное сообщение вместо падения.

$state хранит изменяемые данные, $derived вычисляет значение из них, а $effect выполняет внешнюю синхронизацию. Найдите в примере вход, проверку и место формирования результата.

Хрупкий и проверяемый вариант SvelteKit 3
Что отличает устойчивый проект от случайного запуска. Явные границы делают ошибку локальной и понятной.

Что происходит внутри и почему это работает

Реактивность отслеживает чтение и изменение состояния. Вызов push меняет проксированный массив, поэтому список и производный счётчик обновляются. localStorage доступен только в браузере, что важно для серверного рендеринга SvelteKit. Логику держите отдельно от вывода: функция получает аргумент и возвращает значение, а интерфейс показывает его. Хранение является побочным эффектом, но чтение при инициализации должно учитывать SSR. Проверка browser защищает код от обращения к window на сервере.

ЧастьЗа что отвечаетЧто проверить
$stateхранит поле формы и массив привычекизменение массива обновляет список
$derivedсчитает выполненные элементы из текущего массивазначение совпадает с числом отмеченных checkbox
$effectсохраняет сериализованный массив во внешнее хранилищеперезагрузка возвращает последнее состояние

Не используйте effect для вычисления completed: это производное значение, ему не нужно отдельное изменяемое состояние. Чем меньше дублирующихся переменных, тем меньше расхождений. Effect оставляйте для синхронизации с внешним миром: storage, сетью или сторонним API. Не прячьте поток в одном обработчике: сохраните вход, проверьте его, вызовите операцию и только затем обновите интерфейс.

Проверьте границу Откройте страницу в приватном окне, где localStorage пуст. Интерфейс должен показать 0/0, а не упасть на JSON.parse. Меняйте одно условие за прогон, чтобы видеть причину.

Проверяем проект и добавляем свою функцию

Добавьте удаление привычки и кнопку «Сбросить отметки». Оба действия должны автоматически обновлять счётчик и localStorage. До правки запишите ожидаемое поведение одним предложением. После граничного теста повторите обычный сценарий.

Проверка своими руками
  1. Сохраните ожидаемый результат: новая привычка появляется без перезагрузки, прогресс меняется после клика, а localStorage возвращает список при повторном открытии.
  2. Измените правило: добавьте серию дней и отдельный фильтр «только невыполненные». Сначала предскажите итог.
  3. Передайте граничное значение и убедитесь, что приложение не падает.
  4. Верните корректные данные и объясните роли трёх основных частей.
Готово, если выполняются все пункты
  • страница загружается без ошибок
  • добавление обновляет список сразу
  • счётчик меняется после отметки
  • перезагрузка восстанавливает данные

Хороший Svelte-компонент хранит минимальное состояние и выводит всё остальное из него. Полезная правка проходит от нового ввода до видимого результата.

Четыре контрольные точки SvelteKit 3
Четыре проверки перед следующим шагом. Каждый следующий этап начинается после наблюдаемого результата.

Что запомнить и куда двигаться дальше

Следующий шаг - вынести HabitRow в компонент и добавить серверное хранилище только если данные должны синхронизироваться между устройствами. Для закрепления откройте в проекте React + Vite, в todo list на чистом JavaScript и в офлайн PWA.

Как изучить тему в Кодике

Сначала закрепите события формы, массивы и TypeScript-типы, затем разбирайте runes и SSR. Сначала восстановите главную функцию и проверьте её на трёх значениях.

ШагЧто разобратьМини-проверка
1. ОсноваФормы, массивы, map/filter и localStorageОбъясните вход и выход функции.
2. Инструмент$state, $derived, $effect и условия browserПовторите команду по памяти.
3. ПроектТрекер с добавлением, отметкой и сохранениемПроверьте два сценария.
4. РефакторингКомпоненты, тесты и серверное хранилищеРазделите ввод, логику и вывод.

Удалите localStorage и убедитесь, что основная логика всё ещё работает. Затем верните синхронизацию как отдельный слой. Базовый синтаксис закрепите через курс JavaScript.

localStorage на сервере

Во время SSR объекта window нет. Используйте browser или onMount.

completed как отдельный state

Счётчик расходится с массивом. Вычисляйте его через $derived.

Пустые привычки

Пробелы создают бессмысленные строки. Применяйте trim и ранний return.

Нестабильный ключ списка

Индекс меняется после удаления. Используйте устойчивый id в each-блоке.

Сверяйтесь с первичной документацией. Команды и ограничения примера проверены по официальному релизу SvelteKit 3. Если версия инструмента изменилась, официальный источник важнее старого скриншота.

Что получится в итоге

Готовый результат проекта: SvelteKit 3 для новичка: делаем трекер привычек с нуля
Так выглядит законченный учебный проект: есть понятный вход, видимый результат, защита от неверных данных и место для следующего улучшения.

Короткие ответы
Чем $derived отличается от $state?

$state хранит изменяемое значение, а $derived вычисляется из другого состояния.

Почему localStorage проверяется через browser?

SvelteKit может выполнить компонент на сервере, где браузерных API нет.

Что проверять первым, если SvelteKit 3 не запускается?

Версию среды, текущую папку, команду запуска и первую строку ошибки.

Как понять, что проект SvelteKit 3 работает?

Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай.

Можно ли начать с готового кода?

Да. Добейтесь результата, измените одно правило и восстановите ключевую функцию без копирования.

Сделайте один осознанный шаг дальше

Выберите одно улучшение и проведите его от ввода до результата.

Если не хватает основы, перейдите курс JavaScript, затем восстановите ключевую функцию без подсказки.