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. By default, server-side code must be located in files ending with .server.js for security and performance reasons.
Syntax
{
"/path": {
"hasLoader": true,
"componentPath": "@adminide-stack/user-auth0/lib/components/callback.server.js"
}
}
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 Component with server code by using 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.
To ensure that routes understands there is a .server.js file in addition to componentPath, make sure to set hasServerCode to true.
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:
- Security: Sensitive logic is not included in the client bundle.
- Performance: Smaller client bundles and faster loading times.
- Clarity: Clear distinction between client and server code, improving maintainability.
Back to Index | Previous: Authentication | Next: Middleware System