Dynamic data in the browser
In the browser, your JAMStack app becomes a typical React app and loading data is a common operation.
You're going to learn the declarative query approach to data loading. Both for GraphQL and REST.
In the interest of time, we're doing these exercises with Gatsby. You can use the same approach with NextJS.
GraphQL with Apollo Client
GraphQL creates a flexible interface to your data. It moves flexibility (and complexity) to the frontend so you can iterate faster.
Apollo Client is the most popular GraphQL client and the library that popularized declarative queries. Comes with built-in query caching and request optimizations.
Exercise
Continue with your Gatsby project from before, or jump into mine in exercise-4. Use the SpaceX GraphQL API create a page that lists SpaceX's last 10 launches.
As always with Gatsby, there's a plugin for this.
Install gatsby-plugin-apollo and @apollo/client and enable the plugin in gatsby-config.js:
// gatsby-config.js{resolve: 'gatsby-plugin-apollo',options: {uri: 'https://api.spacex.land/graphql'}}
You can now query the SpaceX API in any React component with the useQuery hook. I suggest making a self-contained <LaunchList> component. Something like this:
import { gql, useQuery } from "@apollo/client"export const LaunchList = () => {const { loading, error, data } = useQuery(gql`{launchesPast(limit: 10) {mission_namelinks {article_linkvideo_link}rocket {rocket_name}}}`)if (loading) {// indicate loading state} else if (error) {// show an error} else {// list launches, they're in data.launchesPast}}
PS: for NextJS, you'll have to wrap _app.js in <ApolloProvider> yourself becuse there's no plugin. The rest stays the same.
Solution
Find mine in the exercise-4-solution branch.
REST with React Query
React Query took the idea of declarative queries from GraphQL and applied it to REST. Comes with many of the same benefits like caching and optimization.
Unlike GraphQL, React Query can't understand your queries, which means it can't optimize at the request fragment level.
Exercise
Use the SpaceX REST API to create a page that lists SpaceX's last 10 launches.
There's no Gatsby plugin for React Query. You'll have to set it up yourself.
Install react-query and wrap your component root in the cache provider. Add it to both gatsby-browser.js and gatsby-ssr.js.
import { QueryCache, ReactQueryCacheProvider } from "react-query"const queryCache = new QueryCache()export const wrapRootElement = ({ element }) => {return (<ReactQueryCacheProvider queryCache={queryCache}>{element}</ReactQueryCacheProvider>)}
You can now query REST APIs from anywhere with the useQuery hook. I recommend creating a new LaunchListREST component. Like this:
import { useQuery } from "react-query"export const LaunchListREST = () => {const { isLoading, error, data } = useQuery(["launches-past"], async () => {const res = await fetch("https://api.spacex.land/rest/launches-past?limit=10")return res.json()})if (loading) {// indicate loading state} else if (error) {// show an error} else {// list launches, they're in data}}
Look at your network log, see the difference in how much data you load with GraphQL vs. REST.
Solution
Find mine in the exercise-4-solution branch.
Wormhole state management
The core benefit of the declarative query approach to data loading is that performance is solved for you. Run the query wherever you need data, don't worry about repeat requests.
Exercise
Take your launches page and add a button that renders a new <LaunchList> and <LaunchListREST> component on the same page. See what happens in your network tab.
Now add a staleness timeout to your REST query and try again.
{staleTime: 5 * 60 * 1000,}
Solution
Find mine in the exercise-4-solution branch.