Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Loading data: createResource and Suspense

A resource is a signal for asynchronous data: it calls the loading function itself, keeps the result and reports whether loading is in progress or an error happened. This is how Solid loads server data without hand-written effects and flags.

From this lesson on, the example becomes a small blog. Create a new project the same way as the to-do list:

npx degit solidjs/templates/js blog
cd blog
npm install
npm run dev

Posts will come from the test API https://jsonplaceholder.typicode.com.

createResource

Create the component src/components/PostList.jsx:

// src/components/PostList.jsx
import { createResource, For, Show } from 'solid-js';
 
const fetchPosts = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
  return res.json();
};
 
export default function PostList() {
  const [posts] = createResource(fetchPosts);
 
  return (
    <Show when={!posts.loading} fallback={<p>Loading...</p>}>
      <ul>
        <For each={posts()}>{(post) => <li>{post.title}</li>}</For>
      </ul>
    </Show>
  );
}

Render <PostList /> in src/App.jsx. At http://localhost:3000 you first see "Loading...", then a list of five post titles.

What a resource has

PropertyValue
posts()The loaded data or undefined
posts.loadingtrue while the request is running
posts.errorThe error, if the request failed

The second element of the pair is an object with the functions refetch (load again) and mutate (replace the data by hand): const [posts, { refetch }] = createResource(fetchPosts).

A resource with a parameter

If you pass a signal as the first argument, the resource reloads each time it changes:

// src/components/PostView.jsx
import { createSignal, createResource, Show } from 'solid-js';
 
const fetchPost = async (id) => {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  return res.json();
};
 
export default function PostView() {
  const [id, setId] = createSignal(1);
  const [post] = createResource(id, fetchPost);
 
  return (
    <div>
      <button onClick={() => setId(id() + 1)}>Next post</button>
      <Show when={post()}>{(p) => <h2>{p().title}</h2>}</Show>
    </div>
  );
}

Each click loads the next post and shows its title. The signal's value arrives in fetchPost as the first argument.

Suspense

Suspense shows fallback content until every resource read inside it has loaded:

// src/App.jsx
import { Suspense } from 'solid-js';
import PostList from './components/PostList';
 
export default function App() {
  return (
    <Suspense fallback={<p>Loading the blog...</p>}>
      <PostList />
    </Suspense>
  );
}

This way you can drop Show from PostList and describe loading once for the whole page.

Common mistake

Loading data in createEffect or onMount and putting it into a signal by hand. It works, but you have to add loading and error flags yourself, and Suspense knows nothing about such a request. For server data use createResource.

Thanks for reading!

Donate to the site — we work hard for you.