Why You Could Switch From Redux to Apollo In React

Erwann BrHm
Kili Technology
Published in
7 min readJun 20, 2022

From Redux to Apollo in React

Redux was released when it was hard to manage states in JS frameworks. Now JS frameworks’ state management improved, reducing the need for a state management library. Now libraries for requesting the backend include their own state management solution. It is the case for Apollo GraphQL client.

Apollo arises as a solution that could become a new standard like redux did.

⚠️ Disclaimer ⚠️ This article explains how and why you could switch from Redux to Apollo, based on our experience at Kili-technology. We decided to shift to Apollo because we wanted to upgrade our application’s speed and maintainability. Keep in mind that you could have different needs than ours.

Redux and Apollo

Wait what is Redux?

Redux is a library, based on Facebook’s Flux Architecture with a limited API designed to be a predictable container for the application state. Allowing you to access and share data across your application. Redux allows to store and update the state of the app in a centralized place.

And Apollo?

Apollo is a state management library for JavaScript that enables you to manage both local and remote data with GraphQL.

Use it to fetch, cache, and modify application data while automatically updating your UI.

How can Apollo replace Redux?

Why do I need to remove Redux? Is it bad to use it?

No, Redux is still a great library that created new standards and redefines how we manage state in our apps and will still be here for the years to come. However, the support for async code, like requests, isn’t built-in unlike libraries such as Apollo or React-query.

Furthermore, Redux becomes harder to use efficiently for huge applications because it introduces a lot of boilerplate code and dependencies. Which means :

  • Harder workflow and code maintainability
  • Easier to introduce an error
  • Which leads to more wasted time on unnecessary issues

Ok, but why is Apollo so great?

The first point here is that Apollo is a GraphQL client library, that comes with tons of benefits. I won’t enter too much in detail in this article but you can find more here if you want to learn about it.

Also, Redux comes with a lot of boilerplate codes, even though some Redux packages like Redux ToolKit, correct some problems such as the installation. Apollo has a different code base allowing to work on these issues while the package was created.

Indeed for a lot of applications nowadays like ours, remote data accounts for the largest part of the application data while only a smaller part is dedicated to real local data. In this case, Redux isn’t the best choice.

Again this is what we decided at Kili. Indeed a lot of client libraries come with remote data management for requests. And since we use GraphQL, we decided to take Apollo. Furthermore, that Apollo comes also with state management, Apollo cache.

If you don’t want to use it there is still plenty of other libraries like React-query or SWR.

That’s why firstly I will show you how to switch from redux to Apollo for your remote data. To do this we will use React with Typescript.

Remote Data Management with Apollo Client

⚠️ Disclaimer ⚠️ The API calls provided in this tutorial are mocked. They only serve as examples.

We will illustrate these queries. They would allow you to do basic operations, like getting, updating, or creating data.

Before we start, I need to tell you that, we will not cover the part of how redux works. I will only do a quick presentation of the files you might have in your app using Redux.

Let’s assume we have a Redux app, it may vary depending on how you implemented redux. Here we use createSlice, createSlice generates action creators and action types that correspond to the reducers and the state you defined. If you want to know more about createSlice.

So are you ready? Here are the most important files for our redux application, the complete codes can be found here.

TodoSlice.ts : to set our redux

ManageTodos

TodoList.tsx :

Quite a lot of work no? Well, let’s simplify all of this!

Really, How much of this can we remove?

Well basically here we need to remove the Redux’s file. For this we will mostly use 2 functions provided by Apollo.

Configure Apollo

First, we need to configure Apollo to enable cache use and all the functions we need.

You connect Apollo Client to React with ApolloProvider component. ApolloProvider wraps your React app and places Apollo Client in the context, which enables you to access it from anywhere in your component tree.

In index.js, let's wrap our React app with an ApolloProvider. We suggest putting the ApolloProvider somewhere high in your app, above any component that might need to access GraphQL data.

Fetching our data with useQuery

First, we need our GraphQL query, here’s what it can look like in our case, note that with GraphQL it’s easy to request exactly what you need and never over fetch. If you want to learn more about what you can do in GraphQL here’s a link to the documentation.

const GET_TODO = gql`
query Todos($todoId: String) {
todos(todoId: $todoId) {
author
id
name
content
}
}
`;

Now we will be able to update our component and we’ll pass our GET_TODO query to useQuery

const { loading, error, data } = useQuery(GET_TODO);

With our request set, we can now define our request using useQuery. useQuery is a hook that you can use with Apollo allowing you to send a request and get several pieces of information such as the data, loading state, etc... Variables like loading for example will update automatically from true to false if the query is loading or not. This allows you to customize your component with the progress of your queries.

Excellent but I don’t understand where is the cache like Redux ?

Whenever Apollo Client fetches query results from your server, it automatically caches those results locally. This makes later executions of that same query extremely fast.

Next, let’s learn some techniques for ensuring that our cached data is updated.

Inside our code, it looks like this

So we did the first step we now have a cached query, but what if I want to update it ?

Good question, Apollo provides you with another tool, useMutation

Here we have our mutation query that will tell GraphQL how and what needs to be updated. TodoWhere and TodoData will be needed when we call the mutation as we will see in a few lines. Remember to add the gql function to parse them into query documents:

const UPDATE_TODO = gql`
mutation UpdateTodo($where: TodoWhere!, $data: TodoData!) {
updateTodo(where: $where, data: $data) {
id
content
completed
}
}
`;

Then we have our mutation with again the result of the query, loading state … But this time we give the mutation as a parameter of useMutation

We can also add a refetchQueries , allowing us to automatically refetch our get query when we update the data. For this we need to pass to useMutation :

  • the mutation query UPDATE_TODO
  • an object
  • refetchQueries with all the queries we want to update GET_TODO
const [updateTodo, { data : updatedData, loading: loadingUpdatedData, error }] = 
useMutation(UPDATE_TODO, {
refetchQueries: [GET_TODO],
});

useMutation returns a mutation function and an object with fields that represent the current status of the mutation's execution similar to useQuery

How do I use it ?

useMutation doesn’t execute automatically on render. You need to call its mutate function, for example when you click on the Save button.

const onSavePostClicked = () => {
if (canSave) {
await updateTodo({
variables: { data: {content}, where: { id } },
});
}
};

With Redux you call an action that gets the data from the store, then calls the API. With React Apollo you write a mutation.

And how do I create a todo?

Well, same procedure as update so we will go through it fast. We need our query:

const CREATE_TODO = gql`
mutation CreateTodo($where: TodoWhere!, $data: TodoData!) {
createTodo(where: $where, data: $data) {
content
completed
}
}
`;

The mutation

const [createTodo, { data : createdData, error }] = 
useMutation(CREATE_TODO, {
refetchQueries: [GET_TODO],
});

The call

const onAddPostClicked = async () => {
if (canSave) {
await createTodos({
variables: { data : {content, id }}
});
}
};

We pass the new data and the Id to update. And … that’s it we have everything we need for our code !

With this, we centralized our code and got rid of redux, yet you are still free to split some of it like the constant in other files.

Apollo was created with the idea of managing remote data, allowing less overhead.

To summarize, Apollo’s advantage we could say that :

  • Apollo checks that if we have the necessary data in the cache we won’t make any unnecessary network calls.
  • Also the Apollo syntax is quite simple and very natural to use.
  • It’s made for remote data management and therefore is more optimized on this point.
  • Compare to redux we need less code. Therefore it’s easier to maintain.

Going Further

In these examples, we saw and learn the way to switch from Redux to Apollo for remote data. However, you still haven’t used the full potential of Apollo. Indeed, Apollo also has its own state and cache management where you can fully replace redux and get rid of the local data management.

There is still room for improvement and I advise you to pursue your research to learn all the possibilities Apollo has to offer, for example, I advise you to have a look at Apollo Cache.

Conclusion

Apollo helped us to simplify our logic for managing remote data and helped us improve our code maintainability while increasing your application speed.

Redux is a great tool If you are looking for a fast, dynamic, simple, and optimized library for your state management. It also comes with an excellent DevTool.

You are interested in this topic? We are a well-funded technology startup working on cutting-edge problems ranging from machine learning to software engineering. Come work with us by contacting angel@kili-technology.com!

--

--

Erwann BrHm
Kili Technology
0 Followers
Writer for

Software engineer at Kili Technology