Skip to main content

Generated Data Loaders

To minimize repetitive work, we automatically generate Remix data loaders by analyzing the page source code. Our parser scans the page for GraphQL queries and calls all of those queries in the generated data loaders.

How It Works

  1. The parser analyzes the component code and detects GraphQL queries.
  2. It creates a key-value pair where the key represents the GraphQL document the query uses, and the value refers to the variables used by the query.
  3. This information is used to generate both server and client loaders.

Example

Consider this component:

// Teams.tsx
const Teams = (props) => {
const [data, { loading }] = useTeamsQuery({ variables: { orgName, pageSize: 10 } });
// rest of the business logic
return (
// component render Markup
)
}

The generated routes.json structure will look like this:

{
"queries": {
"TeamsDocument": "{orgName: params.orgName, pageSize: 10}"
}
}

Generated Loaders

The generator function uses this meta-information to create loaders for both server and client:

export const loaders = ({ params, context }) => {
const { apolloClient: client } = context;
const queries = { GetTeamsDocument: { orgName: params.orgName, pageSize: 10 } };

const organizationTeamsQuery = client.query({
query: GetTeamsDocument,
variables: queries['GetTeamsDocument'],
fetchPolicy: __SERVER__ ? 'network-only' : 'cache-first',
});

return {
data: {
organizationTeamsQuery
}
};
}

const clientLoader = async ({ params, serverLoader }) => {
const client = window.__APOLLO_CLIENT__;
try {
const getKey = (documentName) => camelCase(documentName).replace('Document', '');
const queries = { GetTeamsDocument: { orgName: params.orgName, pageSize: 10 } };
const queryKeys = ['TeamsQuery'];
let shouldCallServerLoader = false;
let response = {};
let cachedData, cacheKey;

cachedData = client.cache.readQuery({
query: GetTeamsDocument,
variables: queries['GetTeamsDocument'],
});
cacheKey = getKey('GetTeamsDocument');

if (!cachedData) {
shouldCallServerLoader = true;
}
if (cachedData && cachedData[cacheKey]) {
response[queryKeys[0]] = Promise.resolve(cachedData[cacheKey]);
}

if (!shouldCallServerLoader) return response;
const serverData = await serverLoader();
let queryKey = queryKeys[0];

if (!serverData[queryKey].then) {
return;
}
serverData[queryKey].then(({ data }) => {
client.cache.writeQuery({
query: GetTeamsDocument,
variables: queries['GetTeamsDocument'],
data,
});
});

return serverData;
} catch (err) {
console.error('Error in clientLoader', err);
}
}

This approach ensures that by the time the component requests the data, it is already available in the Apollo Cache, reducing redundancy and improving performance.

Back to Index | Previous: Query Params Generator | Next: CSS Import and Stylesheet Links