How to Use clientLoader in Remix for Client-Side Data Loading
In Remix,
clientLoader is used to fetch data on the client side after the initial server render, enabling dynamic client-only data loading. You define a clientLoader function in your route module that returns data fetched in the browser, separate from the server loader. This helps keep initial loads fast and supports client-side interactivity.Syntax
The clientLoader is an async function exported from a Remix route module. It runs only in the browser to fetch data after the page loads.
It returns data that your component can use via the useClientLoaderData() hook.
Basic syntax:
export async function clientLoader(): Defines the client-side data fetch.- Returns JSON data or any serializable value.
- Use
useClientLoaderData()inside your component to access the data.
typescript
export async function clientLoader() { const response = await fetch('/api/data'); const data = await response.json(); return data; } import { useClientLoaderData } from '@remix-run/react'; export default function MyComponent() { const data = useClientLoaderData(); return <div>{JSON.stringify(data)}</div>; }
Example
This example shows a Remix route that uses clientLoader to fetch a random joke from a public API after the page loads. The joke is displayed inside the component.
typescript
import { useClientLoaderData } from '@remix-run/react'; export async function clientLoader() { const res = await fetch('https://official-joke-api.appspot.com/random_joke'); if (!res.ok) throw new Error('Failed to fetch joke'); const joke = await res.json(); return joke; } export default function Joke() { const joke = useClientLoaderData(); return ( <main> <h1>Random Joke</h1> <p><strong>{joke.setup}</strong></p> <p>{joke.punchline}</p> </main> ); }
Output
<main>
<h1>Random Joke</h1>
<p><strong>Why did the scarecrow win an award?</strong></p>
<p>Because he was outstanding in his field!</p>
</main>
Common Pitfalls
- Not exporting
clientLoader: Without exporting it, Remix won't run client-side data fetching. - Using server-only APIs:
clientLoaderruns in the browser, so Node.js-only APIs likefswon't work. - Forgetting to use
useClientLoaderData(): This hook is required to access the data returned byclientLoader. - Mixing server
loaderand clientclientLoaderdata: Keep their responsibilities clear to avoid confusion.
typescript
/* Wrong: Using server-only API in clientLoader */ export async function clientLoader() { // const fs = require('fs'); // โ This will fail in the browser // const data = fs.readFileSync('/some/file.txt', 'utf-8'); // return { data }; return { error: 'Cannot use fs in clientLoader' }; } /* Right: Fetching data from an API in clientLoader */ export async function clientLoader() { const res = await fetch('/api/data'); const data = await res.json(); return data; }
Quick Reference
- Export
clientLoaderfrom your route module for client-side data fetching. - Use
useClientLoaderData()hook inside your component to access the data. - clientLoader runs only in the browser, so avoid server-only code.
- Use clientLoader for data that can load after initial render to improve performance.
Key Takeaways
Export an async clientLoader function in your Remix route to fetch data on the client side.
Use the useClientLoaderData() hook inside your component to access clientLoader data.
clientLoader runs only in the browser, so avoid Node.js-only APIs inside it.
Separate clientLoader from server loader to optimize data fetching and page load.
clientLoader is ideal for dynamic data that can load after the initial server render.