Create the Launches Index Page
index.graphql
Create
./app/graphql/index.graphql
query pastLaunchesList($limit: Int! = 10) {launchesPast(limit: $limit, sort: "launch_date_utc", order: "DESC") {idmission_namelinks {flickr_imagesmission_patch}rocket {rocket_name}}}Run
npm run codegen
Create our API wrapper in
./app/utils/api.server.ts
import { getSdk } from "~/graphql/generated";import { GraphQLClient } from "graphql-request";const sdk = getSdk(new GraphQLClient(process.env.GRAPHQL_ENDPOINT!));export { sdk };Create our CSS in
homepage.css./app/styles/homepage.css
.container {padding-top: 20px;display: grid;grid-gap: 30px;grid-template-columns: repeat(auto-fill, 350px);justify-content: center;}/* Card CSS from w3 schools https://www.w3schools.com/howto/howto_css_cards.asp */.card {/* Add shadows to create the "card" effect */box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);transition: 0.3s;border-radius: 5px; /* 5px rounded corners */}/* On mouse-over, add a deeper shadow */.card:hover {box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);}/* Add some padding inside the card container */.card-container {padding: 2px 16px;}/* Add rounded corners to the top left and the top right corner of the image */img {border-radius: 5px 5px 0 0;}Now, we put everything together and create our index page component that displays all the launches we can book cargo on. Update
./app/routes/index.tsx
import {HeadersFunction,json,Link,LoaderFunction,MetaFunction,useLoaderData,} from "remix";import { sdk } from "~/utils/api.server";import { PastLaunchesListQuery } from "~/graphql/generated";import { getSessionData } from "~/utils/auth.server";import styles from "~/styles/homepage.css";interface LoaderData {launches: PastLaunchesListQuery;isLoggedIn: boolean;}// Set page titleexport const meta: MetaFunction = () => {return { title: "Remix Hasura Spacex" };};// Add CSSexport function links() {return [{ rel: "stylesheet", href: styles }];}// Load JS if we are logged inexport let handle = {hydrate: ({ isLoggedIn }: LoaderData) => isLoggedIn,};// Cache the whole HTML page// max-age is low so when we login the login button doesn't still appearexport const headers: HeadersFunction = () => {return {"Cache-Control": "public, max-age=5, s-maxage=345600",};};export const loader: LoaderFunction = async ({ request }) => {const { idToken } = await getSessionData(request);const launches = await sdk.pastLaunchesList({ limit: 10 });return json<LoaderData>({launches,isLoggedIn: !!idToken,},// If JS is loaded, the JSON we fetch on navigation is cached{headers: { "Cache-Control": "public, max-age=3600, s-maxage=604800" },});};export default function Index() {const { launches } = useLoaderData<LoaderData>();return (<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}><section className="container">{launches.launchesPast?.map((launch, index) => {return (<Linkto={`launch/${launch?.id}`}key={launch?.id}// Prefetch pages on mouseover// https://remix.run/docs/en/v1/api/remix#linkprefetch="intent"><div className="card"><imgsrc={launch?.links?.flickr_images?.[0] ??launch?.links?.mission_patch!}alt={`${launch?.mission_name!}`}style={{ width: "100%", height: "400px" }}// We don't want to lazy load above the fold images// You can make this more advancedloading={index === 0 ? "eager" : "lazy"}/><div className="card-container"><h4><b>{launch?.mission_name!}</b></h4><p>{launch?.rocket?.rocket_name!}</p></div></div></Link>);})}</section></div>);}
Did you find this page helpful?
Start with GraphQL on Hasura for Free
- Build apps and APIs 10x faster
- Built-in authorization and caching
- 8x more performant than hand-rolled APIs