Do you prefer JavaScript or TypeScript?
Are you coming from any of the following frameworks?

Solid Primitives

In this page we will be explaining what you need to know to get started with using Solid.js primitives and making use of Solid.js primitives inside and outside your components.

Solid Primitives

First let's start with Solid.js primitves. What are primitives? Primitives are the simplest elements, functions or data types available in any programming language, framework or library. In Solid.js, primitives are the building blocks that will be responsible for governing reactivity within your Solid.js app. Here's a list of Solid.js primitives:

Note: Solid primitives can be used in any scope, they are not required to be used within a component. Solid components do not own their state because they are just setup functions that have nothing to do with the reactivity system after set up.

We will be focusing on the most used primitives, createSignal, createMemo, createEffect and createResource. To have a more in depth understanding of all the primitives Solid.js has, check out the concepts page.

createSignal

createSignal is the most used primitive in Solid.js. It is used to create a reactive state variable. It takes an optional initial value and returns a tuple with the getter function to get the current value and a setter function to set the value. The setter function is used to update the value of the state variable.

createSignal can be used to store almost any type of data type, including objects and arrays. However, in Solid it is advisable to use the createStore primitive to store objects and arrays. This is because createStore is optimized to handle cases of nested reactivity. More on this in the reference section.

js
import { createSignal } from "solid-js";
const [count, setCount] = createSignal(0);
js
import { createSignal } from "solid-js";
const [count, setCount] = createSignal(0);

createSignal doesn't need to be used within a component. It can be used anywhere in your app. Whether it's in a component, a function or even outside of a component or function.

js
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>
);
}
js
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>
);
}

In the example above we have a count state variable that is used to keep track of the current count. We have two functions, increment and decrement that are used to update the count state variable. We also have a component, Counter that uses the count state variable to display the current count.

As you've noticed in the example above, we are using createSignal outside of a component. This is perfectly fine, it is even possible to import your signal from another file and have it still behave reactively. You can use createSignal anywhere in your app since in Solid components do not own their state. In this way solid has state management built in and there is no need for Redux or other state management libraries unless you would like to make use of features specific to them.

createMemo

createMemo is used to create a reactive state variable that is derived from other reactive state variables. It takes a function that returns the value of the state variable and returns a getter function to get the current value.

js
import { createSignal, createMemo } from "solid-js";
const [count, setCount] = createSignal(0);
const double = createMemo(() => count() * 2);
js
import { createSignal, createMemo } from "solid-js";
const [count, setCount] = createSignal(0);
const double = createMemo(() => count() * 2);

In the example above we have a count state variable that is used to keep track of the current count. We also have a double state variable that is derived from the count state variable. The double state variable is a memoized version of the count state variable. This means that the double state variable will only be recomputed when the count state variable changes.

Here's a quick example of how you can make use of createMemo to create a memoized derived state and make use of it in a component.

js
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>
);
}
js
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>
);
}

In the example above we have a count state variable that is used to keep track of the current count. We also have a double state variable that is derived from the count state variable. The double state variable is a memoized version of the count state variable. This means that the double state variable will only be recomputed when the count state variable changes.

Under the hood createMemo uses createComputed to create a computed value. More on the createComputed primitive in the reference section.

createEffect

createEffect is used to create a reactive effect. It takes a function that will be executed whenever the reactive state variables used in the function change.

js
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>
);
}
js
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>
);
}

Each time the state of count changes, the effect will be executed. This is useful for logging, making API calls, etc. Any side effect that you would like to run whenever the state of a reactive state variable changes can be done using createEffect.

createResource

createResource is a simple but very useful primitive that creates a signal that reflects the value of an asynchronous function. It takes in an asynchronous function, optional options and an optional source signal that will be used to fill in the argument of the asynchronous function.

Here's a quick example of how you can use createResource to fetch data from an API.

js
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>
);
}
js
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 returns some pretty cool stuff that you can use to display the state of the resource reactively, as you can see it has a loading property that is a boolean that is true when the resource is loading and false when it is not. It also has an error property that is an error object if there was an error while fetching the resource. createResource also has some options we can make use of to customize the behaviour. Here's a list of them and a short description on what they do.

  • initialValue : The initial value of the resource. This is useful if you want to display something while the resource is loading.
  • name : The name of the resource. This is useful for debugging.
  • deferStream : A boolean that determines whether your app should wait for the resource to finish before rendering to a stream. Note that this is only useful if you're making use of the renderToStream function.
  • ssrLoadFrom : This can be used to tell the resource if it should load it's initial data from the initialValue or from the server. This is useful if you have some server-side data that you would like to assign to this resource. This can be used by passing either 'initial' or 'server' to this option.
  • storage : This option serves as an declarative way for you to store the resource's data. This is useful if you would like to store the data in a cache or something like that. This option takes a function that returns a tuple with two functions, an Accessor and a Setter of types any. Here's an example of how you can use this option.
tsx
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 [store, setStore] = createSignal<any>({});
const [user] = createResource(id, fetcherFunc, {
storage: (init: any) => [store, setStore],
});
tsx
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 [store, setStore] = createSignal<any>({});
const [user] = createResource(id, fetcherFunc, {
storage: (init: any) => [store, setStore],
});

Once the resource's data is resolved in the above code it will be automatically stored in the store signal.

If you want to use multiple signal values within a single resource, you can do so by creating a derived state with the createMemo primitive. You may be wondering why I'm using the createMemo primitive instead of just creating a standard derived state. That's because createMemo will aid in keeping your derived state reactive, whereas if you create a normal derived state, the derived state will not be updated if the state value changes. Here's how it might look in action.

tsx
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);
tsx
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);

This is just a simple way in which you can make use of more than one signal value within a resource.

To know more about Solid primitives you can check out the solid deep dive section