Server/client communication with useLoaderData
Introduction
Section titled โIntroductionโIn the previous step, we learned about route parameters and how to use them to create dynamic routes in Remix. We then accessed this data on the server using the loader
function.
In this next step we will:
- Pass the
category
value to ourNewsCategoryPage
component and display it on the page with theuseLoaderData
hook. - Fix a TypeScript error by using the
invariant
package to tell TypeScript that thecategoryTitle
value should always be a string. - Complete a challenge to create a wireframe layout for the
NewsCategoryPage
using Tailwind CSS.
Passing data to the page
Section titled โPassing data to the pageโSuccess! With our previous step complete, we are now reading the category
value from the URL ๐. We can use this value to fetch the correct data for our page.
Letโs update the loader
function so it returns this value in title-case as part of the json
response.
import { type LoaderFunctionArgs, json } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import { toTitleCase } from '~/utils/stringUtils.ts'
export async function loader({ params }: LoaderFunctionArgs) { const { category } = params
console.log({ category }) const categoryTitle = toTitleCase(category)
return json({}) return json({ categoryTitle })}
export default function NewsCategoryPage() { const { categoryTitle } = useLoaderData<typeof loader>()
return ( <div className="container py-16"> <h2 className="text-h2">Generic news category page</h2> <h2 className="text-h2">{categoryTitle}</h2> </div> )}
Checking the result
Section titled โChecking the resultโNow, head back to your browser and click the links between the different news categories again.
This time, you should see the title of the category displayed in every page, but we didnโt need to hard-code a separate file for every one ๐:
Fixing TypeScript errors
Section titled โFixing TypeScript errorsโFinally, letโs fix that TypeScript error we saw earlier.
We will do this using a package called Invariant. This package will help us to tell TypeScript that the categoryTitle
value will always be a string.
First, import
the package at the top of your news.$category.tsx
file:
import { invariant } from '@epic-web/invariant'import { type LoaderFunctionArgs, json } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import { toTitleCase } from '~/utils/stringUtils.ts'
Next, inside your loader
function, add the following check:
4 collapsed lines
import { invariant } from '@epic-web/invariant'import { type LoaderFunctionArgs, json } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import { toTitleCase } from '~/utils/stringUtils.ts'
export async function loader({ params }: LoaderFunctionArgs) { const { category } = params
invariant(typeof category === 'string', 'Category not found') const categoryTitle = toTitleCase(category)
return json({ categoryTitle })}
9 collapsed lines
export default function NewsCategoryPage() { const { categoryTitle } = useLoaderData<typeof loader>()
return ( <div className="container py-16"> <h2 className="text-h2">{categoryTitle}</h2> </div> )}
The red line has disappeared, and TypeScript now knows that categoryTitle
will always be a string.
Summary
Section titled โSummaryโIn this step, we:
- Read server data from the
loader
function using theuseLoaderData
hook, and displayed it on the page. - Fixed a TypeScript error by using the
invariant
package to tell TypeScript that thecategoryTitle
value will always be a string.