Skip to content

The `useLoaderData` hook

In any given website, there are two main parts to the code that drives it:

  1. Frontend code: This is the code that runs in the user’s browser. It’s written in JavaScript and is responsible for rendering the website and handling user interactions.

  2. 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.

Front and backend code

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…

Take another look at the app/root.tsx file:

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'
export const links: LinksFunction = () => {
return rootLinkElements
}
export { headers, meta } from './__root.client.tsx'
export { action, loader } from './__root.server.tsx'
export default function App() {
const nonce = useNonce()
return (
<Document nonce={nonce}>
<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>
)
}

You’ll notice that we are exporting two functions from this file: action and loader.

export { action, loader } from './__root.server.tsx'

These functions are responsible for fetching data from the server and processing it before it is sent to the frontend.

But where are these functions defined? The line highlighted above says that the action and loader functions are being exported somehow, but we don’t see them in this file. 🧐

That’s because they are defined in a completely separate file: __root.server.tsx. We can communicate between two files in JavaScript using import and export statements.

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…

useLoaderData is a custom React hook supplied for us by Remix.

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:

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 { useLoaderData } from '@remix-run/react'
import ThemeSwitch from '~/components/shared-layout/ThemeSwitch'
import { type loader } from './__root.server'
import useTheme from './hooks/useTheme.tsx'

Next, carefully add the code highlighted in green below to the App component function itself:

app/root.tsx
14 collapsed lines
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 { useLoaderData } from '@remix-run/react'
import ThemeSwitch from '~/components/shared-layout/ThemeSwitch'
import { loader } from './__root.server'
import useTheme from './hooks/useTheme.tsx'
export const links: LinksFunction = () => {
return rootLinkElements
}
export { headers, meta } from './__root.client.tsx'
export { action, loader } from './__root.server.tsx'
export default function App() {
const data = useLoaderData<typeof loader>();
const nonce = useNonce();
const theme = useTheme()
return (
<Document nonce={nonce} theme={theme}>
<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:

Light and dark mode toggle button

You now have a working light and dark mode toggle button in your Remix app! 🚀

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.

  1. Windows: SHIFT + ALT + O
  2. Mac: SHIFT + OPTION + O

Press this shortcut now to automatically organise your imports at the top of your file:

Auto sort imports in root.tsx

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.

In the next step, we will add a navbar and footer to the website to introduce navigation and improve user experience.