Skip to main content

DataClient Architecture

The DataClient is the central state management and data orchestration engine of the Archibald framework. It acts as the "Source of Truth" for all shared application data, handling caching, synchronization, and reactivity across the Server (SSR) and the Client (Browser).


High-Level Role

Unlike traditional state management libraries (like Redux) that focus on local UI state, the DataClient is specifically designed for Asynchronous Server State. Its primary responsibilities include:

  1. Centralized Cache Management: Storing and retrieving data for unique FetchKeys.
  2. Request Deduplication: Ensuring the same data isn't fetched multiple times simultaneously.
  3. SSR & Hydration: Facilitating the transfer of state from the server to the client.
  4. Reactivity: Providing a subscription system that notifies components when data changes.
  5. Synchronization: Handling background refetching (on focus, on intervals, or on hydration).

How it Works

The DataClient operates using a Key-Value Store architecture. Every piece of data is identified by a FetchKey (which can be a string, a number, or an array).

1. The Request Lifecycle

When a component requests data (e.g., via useFetch):

  1. Cache Lookup: The DataClient checks if a valid entry exists for the given key.
  2. State Evaluation: It determines if the data is "stale" or "expired" based on configured ttl (Time to Live) and refetch intervals.
  3. Execution: If needed, it executes the provided data-fetching function.
  4. Notification: Once the request resolves, it updates the DataCache and notifies all subscribers (including the React component).

2. SSR and Hydration Workflow

The DataClient is the bridge for state between environments:

  • On the Server: During SSR, the DataClient collects all data fetched by components. This state is then "dehydrated" (serialized) and injected into the HTML.
  • On the Client: During boot-up, the DataClient "rehydrates" (deserializes) this state into its local cache. This allows the application to render immediately without making initial network requests.

Interactions with Other Services

The DataClient does not work in isolation. It sits at the center of several architectural components:

1. useFetch and useMutation (Hooks)

These are the primary entry points for developers. The hooks act as a reactive layer over the DataClient. They subscribe to specific keys and trigger re-renders when the DataClient updates the corresponding cache entry.

2. DataCache

The DataClient uses DataCache instances to actually store the data. It maintains two separate caches by default:

  • dataCache: For read-only data (queries).
  • mutationCache: For write operations and their results.

3. SubscriberMap

The DataClient inherits from SubscriberMap, which provides the event-driven backbone. It allows any service or component to listen for events like load, mutate, error, or cache:clear.

4. Renderer (Server)

The server-side Renderer interacts with the DataClient to collect the total state before completing the HTML response. It uses the dataClient.compress() method to prepare the state for transport.

5. AppClient

While the DataClient manages State, the AppClient typically handles the Communication. The DataClient often calls methods on the AppClient (or specific feature clients like CartClient) to perform the actual network requests.


Key Concepts

  • Stale-While-Revalidate: The DataClient can return "stale" data from the cache immediately while fetching the fresh version in the background.
  • Garbage Collection: It automatically cleans up old cache entries based on maxEntries and ttl to prevent memory leaks.
  • Concurrency: It manages fetches and mutations sets to keep track of currently active asynchronous operations.