The `useLoaderData` hook
Frontend and backend code
Section titled “Frontend and backend code”In any given website, there are two main parts to the code that drives it:
-
Frontend code: This is the code that runs in the user’s browser (the ‘client’). It’s written in JavaScript and is responsible for rendering the website and handling user interactions.
-
Backend code: This is the code that runs on the server. It’s written in a server-side language like Node.js, Python, or Ruby, and is responsible for fetching data from a database, processing it, and sending it to the frontend.
In a traditional website, the frontend and backend code are separate and communicate with each other using HTTP requests. The frontend code makes a request to the backend code, which processes the request and sends back a response.

In Remix, the frontend and backend code are combined into a single file called a route module. The file we have been working in - root.tsx - is an example of a route module.
This file contains both the frontend code (React components) and the backend code needed to render a particular page.
So far, we have been working exclusively on the frontend code. So where is the backend code? Let’s take a look…
The loader and action functions
Section titled “The loader and action functions”Take another look at the app/root.tsx file:
import { useLoaderData } from 'react-router'import { type Route } from './+types/root.ts'import { type loader } from './__root.server.tsx'import { GeneralErrorBoundary } from './components/error-boundary.tsx'import Document from './components/shared-layout/Document.tsx'import { useNonce } from './utils/nonce-provider.ts'import rootLinkElements from './utils/providers/rootLinkElements.ts'
export const links: Route.LinksFunction = () => { return rootLinkElements}export { meta } from './__root.client.tsx'export { headers, loader } from './__root.server.tsx'
export default function App() { const data = useLoaderData<typeof loader | null>() const nonce = useNonce()
return ( <Document nonce={nonce} honeyProps={data?.honeyProps}> <div className="flex h-screen flex-col justify-between"> <div className="flex-1"> <main className="grid h-full place-items-center"> <h1 className="text-mega">Welcome to Epic News!</h1> </main> </div> </div> </Document> )}
export const ErrorBoundary = GeneralErrorBoundaryYou’ll notice that we are exporting a function from this file called: loader.
export { headers, loader } from './__root.server.tsx'This function is responsible for fetching data from the server and processing it before it is sent to the frontend.
But where is this function defined? The line highlighted above says that the loader function is being exported somehow, but we don’t see them in this file. 🧐
That’s because it is defined in a completely separate file: __root.server.tsx.
If you are interested, open up the __root.server.tsx file and take a look at the loader function. You’ll see that it is responsible for fetching data from the server and sending it to the frontend.
We will be looking more closely at the loader function in a later tutorial.
For now, we just need to get the data from the loader function into the frontend component. Let’s see how we can do that…
Adding useLoaderData to the App component
Section titled “Adding useLoaderData to the App component”useLoaderData is a custom React hook supplied for us by Remix.
Updating the import statements
Section titled “Updating the import statements”Making sure you are still inside app/root.tsx, let’s start by updating the import statements at the top of the file.
Add the code highlighted in green to the end of your import statements in app/root.tsx:
import { type LinksFunction } from '@remix-run/node'import Document from '~/components/shared-layout/Document'import { useNonce } from '~/utils/nonce-provider.ts'import rootLinkElements from '~/utils/providers/rootLinkElements'import { ThemeSwitch, useTheme } from './routes/resources+/theme-switch.tsx'Next, carefully add the code highlighted in green below to the App component function itself:
14 collapsed lines
import { useLoaderData } from 'react-router'import { type Route } from './+types/root.ts'import { type loader } from './__root.server.tsx'import { GeneralErrorBoundary } from './components/error-boundary.tsx'import Document from './components/shared-layout/Document.tsx'import { useNonce } from './utils/nonce-provider.ts'import rootLinkElements from './utils/providers/rootLinkElements.ts'import { ThemeSwitch, useTheme } from './routes/resources+/theme-switch.tsx'
export const links: LinksFunction = () => { return rootLinkElements}export { meta } from './__root.client.tsx'export { headers, loader } from './__root.server.tsx'
export default function App() { const data = useLoaderData<typeof loader | null>(); const nonce = useNonce(); const theme = useTheme()
return ( <Document theme={theme} nonce={nonce} honeyProps={data?.honeyProps}> <div className="flex h-screen flex-col justify-between"> <div className="flex-1"> <main className="grid h-full place-items-center"> <h1 className="text-mega">Welcome to Epic News!</h1> </main> </div>
<div className="container flex justify-between pb-5"> <ThemeSwitch userPreference={data?.requestInfo.userPrefs.theme} /> </div> </div> </Document> )}Testing the light and dark mode toggle button
Section titled “Testing the light and dark mode toggle button”Save your changes, then head back to the browser. You should now be able to toggle the theme between light and dark mode by clicking the button:

🎉 Congratulations! 🎉
Section titled “🎉 Congratulations! 🎉”You now have a working light and dark mode toggle button in your Remix app! 🚀
Automatically organise imports in VS Code
Section titled “Automatically organise imports in VS Code”Finally, lets fix the yellow underlines that might still be showing under your new import statements.
As mentioned earlier, VS Code is warning us that we haven’t used the values, variables and functions that we are importing yet.
Thankfully, VS Code provides us with a keyboard shortcut to automatically organise our imports in the correct order.
- Windows: SHIFT + ALT + O
- Mac: SHIFT + OPTION + O
Press this shortcut now to automatically organise your imports at the top of your file:

Remember to save your file after you have done this, and commit your changes to Git.
Support your explanations with screenshots and code snippets where necessary.
What’s next?
Section titled “What’s next?”In the next step, we will add a navbar and footer to the website to introduce navigation and improve user experience.