Introduction
In our last GraphQL article we took a look at the basis of setting up a GraphQL backend with graphene to get an idea of what goes on in the backend. For to0day, just grab a cup of coffee, and let’s dive into why working with React using GraphQL for data fetching. With the right idea this duo is like peanut butter and jelly ... perfect together.
Setting Up the Environment
First things first, let’s set up our development environment. You’ll need Node.js and npm (or Yarn) installed on your machine. Once you have those, let’s create a new React project. Open your terminal and run:
npx create-react-app graphql-react-app
cd graphql-react-app
Now, we need to bring in Apollo Client, which is an awesome library for managing GraphQL in your frontend. Run:
npm install @apollo/client graphql
Integrating Apollo Client
Next up, we need to integrate Apollo Client with our React app. This involves setting up an Apollo Client instance and making it available to our components. Create a new file called src/ApolloClient.js
and add the following code:
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:5000/graphql',
cache: new InMemoryCache()
});
const ApolloProviderWrapper = ({ children }) => (
<ApolloProvider client={client}>
{children}
</ApolloProvider>
);
export default ApolloProviderWrapper;
What we’ve done here is create an Apollo Client instance that points to our GraphQL server and set up an ApolloProvider
to wrap our React app, making the client available to all our components.
Now, let’s wrap our app with ApolloProviderWrapper
in src/index.js
:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import ApolloProviderWrapper from './ApolloClient';
ReactDOM.render(
<ApolloProviderWrapper>
<App />
</ApolloProviderWrapper>,
document.getElementById('root')
);
Writing Queries and Mutations
With Apollo Client all set up, let’s write some GraphQL queries. Create a new file called src/queries.js
and add a simple query:
import { gql } from '@apollo/client';
export const GET_GREETING = gql`
query GetGreeting {
hello
}
`;
Now, let’s use this query in our React component. Open src/App.js
and update it as follows:
import React from 'react';
import { useQuery } from '@apollo/client';
import { GET_GREETING } from './queries';
function App() {
const { loading, error, data } = useQuery(GET_GREETING);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div className="App">
<h1>{data.hello}</h1>
</div>
);
}
export default App;
In this setup, we use Apollo’s useQuery
hook to fetch data from our GraphQL server. If the data is still loading, we show a loading message. If there’s an error, we show an error message. Otherwise, we display the fetched data.
Handling State and UI Updates
Apollo Client also helps manage local state and UI updates efficiently. Let’s say you want to handle a form submission and update the UI with the new data. Create a new mutation in src/queries.js
:
export const ADD_GREETING = gql`
mutation AddGreeting($message: String!) {
addGreeting(message: $message) {
message
}
}
`;
Now, let’s create a form component to handle the mutation. Create src/GreetingForm.js
:
import React, { useState } from 'react';
import { useMutation } from '@apollo/client';
import { ADD_GREETING, GET_GREETING } from './queries';
function GreetingForm() {
const [message, setMessage] = useState('');
const [addGreeting] = useMutation(ADD_GREETING, {
update(cache, { data: { addGreeting } }) {
const { hello } = cache.readQuery({ query: GET_GREETING });
cache.writeQuery({
query: GET_GREETING,
data: { hello: [...hello, addGreeting.message] },
});
}
});
const handleSubmit = async (e) => {
e.preventDefault();
await addGreeting({ variables: { message } });
setMessage('');
};
return (
<form onSubmit={handleSubmit}>
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter a greeting"
/>
<button type="submit">Submit</button>
</form>
);
}
export default GreetingForm;
In this component, we use Apollo’s useMutation
hook to send a mutation to our GraphQL server. When the mutation is successful, we update Apollo’s cache to reflect the new data, which automatically updates our UI.
Finally, let’s update src/App.js
to include our new form component:
import React from 'react';
import { useQuery } from '@apollo/client';
import { GET_GREETING } from './queries';
import GreetingForm from './GreetingForm';
function App() {
const { loading, error, data } = useQuery(GET_GREETING);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div className="App">
<h1>{data.hello}</h1>
<GreetingForm />
</div>
);
}
export default App;
Conclusion
And there you have it! GraphQL + React makes magic. Happy coding!