DEV Community

Jonathan Gamble
Jonathan Gamble

Posted on

1

Copying Nuxt's useState in Qwik and Svelte

Nuxt has an amazing tool that allows you to easily share a signal called useState.

Shared State

Nuxt provides a perfect example:

// composables/states.ts

export const useColor = () => useState<string>('color', () => 'pink')
Enter fullscreen mode Exit fullscreen mode

And you can can call the useColor hook from any component.

<script setup lang="ts">
// ---cut-start---
const useColor = () => useState<string>('color', () => 'pink')
// ---cut-end---
const color = useColor() // Same as useState('color')
</script>

<template>
  <p>Current color: {{ color }}</p>
</template>
Enter fullscreen mode Exit fullscreen mode

Let's duplicate this in other frameworks!

SvelteKit

Super easy, similar to my previous posts on the subject.

import { getContext, hasContext, setContext } from "svelte";

export const useState = <T>(
    key: string,
    init?: () => T
) => {

    if (hasContext(key)) {
        return getContext<{ value: T }>(key);
    }

    if (!init) {
        throw new Error('You must initialize in the parent component!');
    }

    const initialValue = init();

    const state = $state<{ value: T }>({
        value: initialValue
    });

    setContext(key, state);
    return state;
};
Enter fullscreen mode Exit fullscreen mode

We can call it just the same:

import { useState } from "./use-state.svelte";

export const useCounter = () => useState('counter', () => 1);
Enter fullscreen mode Exit fullscreen mode

Beautifantastic!

Qwik

A few more steps...

import {
    createContextId,
    type Signal,
    useContext,
    useContextProvider,
    useSignal
} from "@builder.io/qwik";

const useSharedContext = <T>(name: string) =>
    createContextId<T>('io.builder.qwik.' + name);

const useGetShared = <T extends object>(name: string) =>
    useContext<T, null>(useSharedContext(name), null);

const useCreateShared = <T extends object>(name: string, content: T) =>
    useContextProvider<T>(useSharedContext(name), content);


export const useState = <T>(
    key: string,
    init?: () => T,
) => {

    const shared = useGetShared<Signal<T>>(key);
    if (shared) {
        return shared;
    }

    if (!init) {
        throw new Error('You must initialize in the parent component!');
    }

    const initialValue = init();
    const state = useSignal(initialValue);
    useCreateShared(key, state);
    return state;
};
Enter fullscreen mode Exit fullscreen mode

And you call it the same way!

import { useState } from "./use-state";

export const useCounter = () => useState('counter', () => 1);
Enter fullscreen mode Exit fullscreen mode

That's it!

Now we can use the best part of Nuxt in SvelteKit and Qwik!

Demo SvelteKit: Vercel Serverless
Repo SvelteKit: GitHub
Demo Qwik: Vercel Serverless
Repo Qwik: GitHub

I'm a nerd.

Note: I didn't create this for Solid nor React because you can't conditionally run hooks. However, see my Universal Providers article for something similar.

Quadratic AI

Quadratic AI – The Spreadsheet with AI, Code, and Connections

  • AI-Powered Insights: Ask questions in plain English and get instant visualizations
  • Multi-Language Support: Seamlessly switch between Python, SQL, and JavaScript in one workspace
  • Zero Setup Required: Connect to databases or drag-and-drop files straight from your browser
  • Live Collaboration: Work together in real-time, no matter where your team is located
  • Beyond Formulas: Tackle complex analysis that traditional spreadsheets can't handle

Get started for free.

Watch The Demo 📊✨

Top comments (0)

👋 Kindness is contagious

DEV works best when you're signed in—unlocking a more customized experience with features like dark mode and personalized reading settings!

Okay