Getting started/Getting started

Getting started

Fetchium is a reactive data-fetching library built on Signalium. It gives you class-based query definitions, automatic entity normalization and caching, a type DSL for describing API shapes, and first-class React integration --- all driven by Signalium's fine-grained reactivity engine.

With Fetchium you define your API surface as plain classes. The library handles fetch deduplication, caching, staleness, background refetching, offline support, and entity identity so your components stay simple and your data stays consistent.


Quick Start Guide

1. Install the packages

bash
# Using npm
npm install fetchium signalium

# Using yarn
yarn add fetchium signalium

# Using pnpm
pnpm add fetchium signalium

2. Setup the Babel transform

Signalium requires a Babel transform to enable async reactivity. Add it to your bundler config so that async dependency tracking works correctly.

Vite + React

js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { signaliumPreset } from 'signalium/transform';

export default defineConfig({
  plugins: [
    react({
      babel: {
        presets: [signaliumPreset()],
      },
    }),
  ],
});

babel.config.js

js
import { signaliumPreset } from 'signalium/transform';

module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
    '@babel/preset-typescript',
    signaliumPreset(),
  ],
};

3. Create a QueryClient and wrap your app

Every Fetchium app needs a QueryClient backed by a store. The client manages query instances, the entity cache, and network state. Wrap your component tree in a ContextProvider so that queries can find the client.

tsx
import { QueryClient, QueryClientContext } from 'fetchium';
import { ContextProvider } from 'signalium/react';

const client = new QueryClient();

function App() {
  return (
    <ContextProvider contexts={[[QueryClientContext, client]]}>
      <YourApp />
    </ContextProvider>
  );
}

This is the minimal setup. The store defaults to an in-memory cache and RESTQueryAdapter is auto-instantiated on first use with globalThis.fetch. When you need a baseUrl, auth headers, or persistent storage, pass explicit options --- see Project Setup.

Want to go deeper?

For a complete guide to configuring baseUrl, auth headers, persistent stores, and project structure, see Project Setup.

4. Define an Entity and a Query

Entities describe the shape of your API resources. Queries describe how to fetch them. Both use the t type DSL for field definitions.

tsx
import { t, Entity } from 'fetchium';
import { RESTQuery } from 'fetchium/rest';

class User extends Entity {
  __typename = t.typename('User');
  id = t.id;

  name = t.string;
  email = t.string;
}

class GetUser extends RESTQuery {
  params = { id: t.number };

  path = `/users/${this.params.id}`;

  result = { user: t.entity(User) };
}

t.typename and t.id identify the entity for normalization and deduplication. path uses template literal interpolation with this.params to embed parameter values. t.entity(User) tells Fetchium to parse and normalize the response as a User entity.

5. Use the query in a component

tsx
import { useQuery } from 'fetchium/react';

function UserProfile({ userId }: { userId: number }) {
  const result = useQuery(GetUser, { id: userId });

  if (!result.isReady) return <div>Loading...</div>;
  if (result.isRejected) return <div>Error: {result.error.message}</div>;

  return (
    <div>
      <h1>{result.value.user.name}</h1>
      <p>{result.value.user.email}</p>
    </div>
  );
}

Both approaches return a ReactivePromise with properties like value, error, isPending, isReady, isResolved, and isRejected. The component re-renders automatically when the query state changes.


Next Steps

Project Setup

Configure baseUrl, auth, stores, and project structure for production

Queries

Deep dive into query definitions, the template system, and usage patterns

Entities

Understand normalized entity caching and identity-stable proxies

Auth & Headers

Add authentication tokens and custom headers to your requests