Skip to main content

Loaders and Data Fetching in routes.json

This document explains how to configure and use loaders, actions, and handle server-side and client-side code separation in your routes using the routes.json file.

Server-Side Loaders

Server-side loaders are used to fetch data on the server before rendering a component. They are configured using the hasLoader field in routes.json.

Syntax

{
"/path": {
"hasLoader": true
}
}

Implementation

When hasLoader is set to true, you need to implement a loader function in your route file:

export const loader = async ({ params, context }) => {
// Fetch data here
return { data };
};

Handling Server-Side Code with hasServerCode

Remix recommends separating server-side logic into .server.js files for security and performance reasons. When the hasServerCode flag is set to true, it means that server-side code like loaders, actions, and headers will be located in a .server.js file, while client-side logic remains in the main component file.

Example Configuration When hasServerCode is true

{
"/login": {
"hasLoader": true,
"hasServerCode": true,
"componentPath": "@adminide-stack/user-auth0-browser-ant/lib/components/Login/index.js"
}
}

Generated Wrapper When hasServerCode is true

import OriginalComponent from '@adminide-stack/user-auth0-browser-ant/lib/components/Login/index.js';
import { loader as loaderFunc } from '@adminide-stack/user-auth0-browser-ant/lib/components/Login/index.server.js';

Example Configuration When hasServerCode is false

{
"/login": {
"hasLoader": true,
"hasServerCode": false,
"componentPath": "@adminide-stack/user-auth0-browser-ant/lib/components/Login/index.js"
}
}

Generated Wrapper When hasServerCode is false

import OriginalComponent, { loader as loaderFunc } from '@adminide-stack/user-auth0-browser-ant/lib/components/Login/index.js';

By separating the server-side code into .server.js files, we ensure that sensitive server-side logic is not included in the client bundle, as recommended by Remix.

Client-Side Loaders

Client-side loaders are used to fetch data on the client after the initial render. They are configured using the hasClientLoader field in routes.json.

Syntax

{
"/path": {
"hasClientLoader": true
}
}

Implementation

When hasClientLoader is set to true, you need to implement a client loader function:

export const clientLoader = async ({ params }) => {
// Fetch data here
return { data };
};

Actions for Form Submissions and Mutations

Actions are used for handling form submissions and mutations. They are configured using the hasAction field in routes.json.

Syntax

{
"/path": {
"hasAction": true
}
}

Implementation

When hasAction is set to true, you need to implement an action function:

export const action = async ({ request }) => {
// Handle form submission or mutation here
return { result };
};

Integrating Loaders with Authentication and Authorization

Loaders can be integrated with authentication and authorization by checking the user's permissions before fetching data:

export const loader = async ({ params, context }) => {
const { user } = context;
if (!user) {
throw new Error('Unauthorized');
}
if (!user.hasPermission('required.permission')) {
throw new Error('Forbidden');
}
// Fetch data here
return { data };
};

Why Separating Server-Side Code Matters

Separating server-side code into .server.js files provides the following benefits:

  1. Security: Sensitive logic is not included in the client bundle.
  2. Performance: Smaller client bundles and faster loading times.
  3. Clarity: Clear distinction between client and server code, improving maintainability.

Back to Index | Previous: Authentication and Authorization | Next: GraphQL Integration