Load and display article data
Introduction
Section titled βIntroductionβWe are now ready to load articles from the database and display them on the page.
To do this, we will use the prisma
client to fetch all articles from the database first.
Updating the loader
function
Section titled βUpdating the loader functionβOpen app/routes/news.$category.tsx
.
Take a look at the loader
function that we created in this file, and take a moment to remind yourself what it does:
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 })}
const WireframeBlock = () => { return ( <div className="h-72 animate-pulse rounded-lg bg-gray-200 dark:bg-gray-700" /> )}
export default function NewsCategoryPage() { const { categoryTitle } = useLoaderData<typeof loader>()
return (16 collapsed lines
<div className="container py-16"> <h2 className="mb-8 text-h2">{categoryTitle}</h2>
<div className="grid grid-cols-2 gap-6 md:grid-cols-3 lg:grid-cols-5"> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> <WireframeBlock /> </div> </div> )}
Import the prisma
client
Section titled βImport the prisma clientβAdd an import
to the prisma
client at the top of the file:
import { invariant } from '@epic-web/invariant'import { json, type LoaderFunctionArgs } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import techIcon from '~/assets/png/news-categories/tech-logo@2x.png'import { prisma } from '~/utils/db.server.ts'
Fetch all database articles
Section titled βFetch all database articlesβNext, letβs fetch all articles from the database using the prisma
client inside the loader
function, and then export them as JSON:
5 collapsed lines
import { invariant } from '@epic-web/invariant'import { json, type LoaderFunctionArgs } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import { toTitleCase } from '~/utils/stringUtils'import siteLogo from '~/assets/png/epic-news-logo@2x.png'import techIcon from '~/assets/png/tech-logo@2x.png'import { prisma } from '~/utils/db.server.ts'
export async function loader({ params }: LoaderFunctionArgs) { const { category } = params
invariant(typeof category === 'string', 'No category provided') const categoryTitle = toTitleCase(category)
const allArticles = await prisma.article.findMany({ select: { id: true, title: true, category: { select: { name: true } }, images: { select: { id: true } }, }, })
return json({ categoryTitle, allArticles })}
Display article data
Section titled βDisplay article dataβNow that we have fetched all the articles from the database, letβs display them on the page.
At first, we will just display the title and category of each article within the grid that we populated with wireframe blocks earlier.
-
Firstly, delete the
WireframeBlock
components from the page, as we donβt need them anymore:app/routes/news.$category.tsx 23 collapsed linesimport { invariant } from '@epic-web/invariant'import { type LoaderFunctionArgs, json } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import { prisma } from '~/utils/db.server.ts'import { toTitleCase } from '~/utils/stringUtils.ts'export async function loader({ params }: LoaderFunctionArgs) {const { category } = paramsinvariant(typeof category === 'string', 'Category not found')const categoryTitle = toTitleCase(category)const allArticles = await prisma.article.findMany({select: {id: true,title: true,category: { select: { name: true } },images: { select: { id: true } },},})return json({ categoryTitle, allArticles })}const WireframeBlock = () => {return (<div className="h-72 animate-pulse rounded-lg bg-gray-200 dark:bg-gray-700" />)}export default function NewsCategoryPage() {const { categoryTitle } = useLoaderData<typeof loader>()return (<div className="container py-16"><h2 className="mb-8 text-h2">{categoryTitle}</h2><div className="grid grid-cols-2 gap-6 md:grid-cols-3 lg:grid-cols-5"><WireframeBlock /><WireframeBlock /><WireframeBlock /><WireframeBlock /><WireframeBlock /><WireframeBlock /><WireframeBlock /><WireframeBlock /><WireframeBlock /><WireframeBlock /></div></div>)} -
Next, we will return
allArticles
from theuseLoaderData
function that we now have access to, and loop through the articles using amap
function.app/routes/news.$category.tsx 23 collapsed linesimport { invariant } from '@epic-web/invariant'import { type LoaderFunctionArgs, json } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import { prisma } from '~/utils/db.server.ts'import { toTitleCase } from '~/utils/stringUtils.ts'export async function loader({ params }: LoaderFunctionArgs) {const { category } = paramsinvariant(typeof category === 'string', 'Category not found')const categoryTitle = toTitleCase(category)const allArticles = await prisma.article.findMany({select: {id: true,title: true,category: { select: { name: true } },images: { select: { id: true } },},})return json({ categoryTitle, allArticles })}export default function NewsCategoryPage() {const { categoryTitle, allArticles } = useLoaderData<typeof loader>()return (<div className="container py-16"><h2 className="mb-8 text-h2">{categoryTitle}</h2><div className="grid grid-cols-2 gap-6 md:grid-cols-3 lg:grid-cols-5">{allArticles.map(article => (<div key={article.id}><h3>{article.title}</h3><p>{article.category?.name || 'General News'}</p></div>))}</div></div>)} -
Save the file and check the browser to see the unstyled article data displayed on the page:
-
Letβs make them a little clearer by adding a background and some padding to each article βcardβ:
app/routes/news.$category.tsx 23 collapsed linesimport { invariant } from '@epic-web/invariant'import { type LoaderFunctionArgs, json } from '@remix-run/node'import { useLoaderData } from '@remix-run/react'import { prisma } from '~/utils/db.server.ts'import { toTitleCase } from '~/utils/stringUtils.ts'export async function loader({ params }: LoaderFunctionArgs) {const { category } = paramsinvariant(typeof category === 'string', 'Category not found')const categoryTitle = toTitleCase(category)const allArticles = await prisma.article.findMany({select: {id: true,title: true,category: { select: { name: true } },images: { select: { id: true } },},})return json({ categoryTitle, allArticles })}export default function NewsCategoryPage() {const { categoryTitle, allArticles } = useLoaderData<typeof loader>()return (<div className="container py-16"><h2 className="mb-8 text-h2">{categoryTitle}</h2><div className="grid grid-cols-2 gap-6 md:grid-cols-3 lg:grid-cols-5">{allArticles.map(article => (<div className="bg-red-900 p-4" key={article.id}><h3>{article.title}</h3><p>{article.category?.name || 'General News'}</p></div>))}</div></div>)} -
Save the file and check the browser to see the styled article data displayed on the page:
Summary
Section titled βSummaryβIn this guide, we learned how to:
- Use the
select
option in Prisma to only return the fields we need from a database. - Load real articles from the database and display them on the page.
- Loop through these real articles using JavaScriptβs
map
function and display them on the page. - Style the article cards in line with your brand design.
In the next guide, we will learn how to filter articles by the correct category.