Storybook & Atomic Design – 1.14. – Apollo Provider

In this lesson, we'll be extending our layout wrapper component to include Apollo, but first, what exactly is Apollo and why do we need it in our application?

As our future application may (in our case will) require interfacing with a GraphQL schema, we will need a method of querying and mutating information within the browser.

Enter Apollo

Fortunately, there is a powerful React solution named Apollo.

Apollo will act as our method of communicating with the GraphQL schema during runtime, allowing us to query and mutate our API directly within our React components.

Read more about Apollo and how it works with React at - https://www.apollographql.com/docs/react/

To get started, we'll first create a new directory named apollo in our particles directory with a single file provider.jsx -

- __Storybook__
   - __components__
     - __particles__
       - __apollo__
         - provider.jsx

After creating the directory and files, we'll need to install quite a few packages to support us in constructing our Apollo Provider component.

Run the following command from a console in your projects parent directory.

npm i @apollo/react-hooks apollo-boost graphql

provider.jsx

Finally, we will compose our Apollo Wrapper component which will allow us to tap into our GraphQL schema within any component using Apollo functions.

Again, you can think of this similar to how we constructed the ThemeProvider for our global layout component, by creating a HOC (High Order Component) which feeds data or functions to children components.


We first need to import ApolloProvider from @apollo/react-hooks to allow us to reference the provider component and pass in our client value which we'll create with the ApolloClient function from apollo-boost.

To create a new client, we will need to pass in one argument to our ApolloClient function, which is an object with a key of uri and the URL of the GraphQL API we want to interface with.

Next, we'll create our custom ApolloWrapper React component which will accept children (all children components in our application) and construct an ApolloProvider surrounding the component, allowing all children (including our stories) to query and mutate our external API

import React from "react";
import { ApolloProvider } from "@apollo/react-hooks";
import ApolloClient from "apollo-boost";

const client = new ApolloClient({
	uri: "<http://celticwordpress.co.uk/graphql>"
});

const ApolloWrapper = ({ children }) => (
	<ApolloProvider client={client}>{children}</ApolloProvider>
);

export default ApolloWrapper;

Then we will import our new provider to our global decorator layout wrapper (.storybook/config.js), and wrap all of our children components within the ApolloWrapper component, allowing all children to send queries and mutations to our schema.

import React from "react";
import { addDecorator, configure } from "@storybook/react";
import { ThemeProvider } from "styled-components";

import ApolloWrapper from "../components/particles/apollo/provider";
import GlobalStyles from "../components/particles/globalStyles";
import themeDefault from "../components/particles/themeDefault";

// automatically import all files ending in *.stories.js
configure(require.context("../components", true, /\.stories\.js$/), module);

const GlobalWrapper = storyFn => (
	<ApolloWrapper>
		<ThemeProvider theme={themeDefault}>
			<GlobalStyles />
			{storyFn()}
		</ThemeProvider>
	</ApolloWrapper>
);

addDecorator(GlobalWrapper);

My First Apollo GraphQL Query

To make use of our new ApolloWrapper particle functionality, I've gone ahead and included a GraphQL query in our Homepage component.

The GraphQL query interfaces with a WooCommerce WPGraphQL store and returns a list of products in the store with the value of their name (titles).

We can then use this query in our application with a useQuery hook, destructuring the values of data, error, and loading to manage our homepage layout.

If the query is still processing we will return a message of 'Loading...'.

If we hit an error with our query we get an upset error message returned.

But, but, but!

If everything went well, we'll have a JSON payload response in data that we can map over to return a list of products available in our store!

homepage.jsx

import React from "react";
import { useQuery } from "@apollo/react-hooks";
import { gql } from "apollo-boost";

import Banner from "../../organisms/banner/banner";
import Carousel from "../../organisms/carousel/carousel";
import Footer from "../../organisms/footer/footer";
import Header from "../../organisms/header/header";

const EXCHANGE_RATES = gql`
	query {
		products {
			nodes {
				name
			}
		}
	}
`;

const Homepage = ({ banner, carousel, footer, header }) => {
	const { loading, error, data } = useQuery(EXCHANGE_RATES);

	if (loading) return <p>Loading...</p>;
	if (error) return <p>Error :(</p>;

	return (
		<>
			<Header {...header} />
			<h2>Products</h2>
			{data.products.nodes.map(({ name }) => (
				<h3>{name}</h3>
			))}
			<Banner {...banner} />
			<Carousel {...carousel} />
			<Footer {...footer} />
		</>
	);
};

export default Homepage;

Conclusion

Oh boy did we cover a tonne in this lesson.

If you didn't quite understand any of the subjects we covered in this lesson, don't worry as the configuration is definitely advanced and most of the concepts go over my head at times.

Just as long as you can get your <ApolloProvider> working then you'll be in a great place to benefit from the Apollo functionality with the use of Apollo hooks in your application.

Further Reading

Continue Reading 📚