Still using Redux, do you want to try graphql and Apollo?

Time:2021-3-9

Still using Redux, do you want to try graphql & Apollo?

Still using Redux, do you want to try graphql and Apollo?

Some time ago, when I was using Twitter, I saw big V mention Apollo one after another, predicting that it will rise in 2018. I happened to have the opportunity to use graphql. After looking through Apollo’s documents, I decided to try to use Apollo to write the data layer in a new front-end project instead of the familiar redux. Now, a month later, I must come out to praise this “Sun God”.

GraphQL

In the twinkling of an eye, in 2018, graphql is no longer a new term. After a brief wave of discussions for 15 years, it seems that few of its voices have been heard. However, GitHub has gradually matured in recent years, and GitHub has also implemented the new API completely with graphql. I won’t discuss graphql itself here. It makes the data acquisition between the front end and the back end easier.

Redux

When it comes to front-end data management, the first thing that comes to mind is redux. I think many people have experienced various stages from being unfamiliar with Redux to being familiar with it. It should be like this:

Still using Redux, do you want to try graphql and Apollo?

  • Start: the flux architecture designed by Facebook is very powerful. Everyone is using it, so I’ll use it too
  • Half a year: the data management becomes clearer, and finally there is no need to go back and forth in the components of the chaotic set state
  • One year: I’m a crud engineer. I write a stereotyped list. It’s really frustrating to use Redux for form pages. How much more code
  • A year and a half: watched Redux action, Redux promise, DVA, mirror… And customized the most suitable middleware and plug-in according to the business scenario of the team. The code is simple again
  • Two years: what should be tossed has been tossed. A little tired, but also inseparable.

Why are you tired? Because the one-way data flow of flux is no longer new to you. Most of the time, the data stored in the store is requested from the back end. For them, how to do dispatch and reduce is not the key, but how to design the store is worth considering.

When Redux meets business needs

Let’s take a real scene as an example

Still using Redux, do you want to try graphql and Apollo?

This is a very common comment list. After we get the demand, we start to write our comments<Comments />Under the Redux paradigm, it’s hard to avoid following this logic:

  1. stayCommentsOfdidMountInside,dispatchA way to get dataactionIn thisfetch actionSend the request within. In order to do loading, we probably need to dispatch another action to inform Redux that we have initiated a request.
  2. If the request is successful, we dispatch an action that requests the data successfully, and then process and update the data in the reducer.
  3. stayCommentsWe received the data from props and started rendering

A lot of our work is spent on how to get the data. And what are the challenges we face? Look at some of the requirements that product managers may ask

  1. When users create or modify comments, they should be able to see the updates in the list immediately;

Simple, request the entire list interface again! Generally speaking, that’s enough, but demanding products may require you to do “optimistic” updates to make the experience better. That’s no problem. Add onereducernamely.

  1. When the mouse hovers over the user’s Avatar, the user’s detailed data (profile, contact information…) will pop up

First of all, you will think, can the back-end elder brother add these fields to the interface data of the comments for me? He refuses you without hesitation and takes out a commonuser interface for you to tune. If you think about it carefully, the amount of user data is not small, and there are a large number of the same users in the comments, so it’s really reasonable not to put them in the list. Heart a horizontal, simply the front-end data structure here all normalize, according to the user ID as key, with hash table to store data. Just one afternoon, you got a perfect solution.

Faced with such a scene, we wrote too muchImperativeCode, we describe step by step how to get the comment data, extract all the user ID after getting the comment data, request to get all the user data again after de duplication, and so on. We also need to consider the details of cache, normalize, optimistic update and so on. And these are exactly what Redux can’t help us. So we will encapsulate more powerful libraries and frameworks based on Redux, but it seems that we haven’t really seen a very suitable focus in data acquisition.

Declarative vs imperative

So what’s it like in Apollo’s world?

import { graphql } from 'react-apollo';

const CommentsQuery = gql`
    query Comments() {
        comments {
            id
            content
            creator {
                id
                name
            }
        }
    }
`;

export default graphql(CommentsQuery)(Comments);

We used itgraphql(analogy to connect in Redux) as a high-level component, bind a query statement of graphql to the comments component, and then you are ready for everything. Is it that simple? Yes, we no longer need to describe how to send requests in didmount and how to process the requested data. Instead, we entrust Apollo to help us deal with all these things. It will be competent to help us send requests to get data when we need it, and then map the data to the props of comments and give it to us.

Still using Redux, do you want to try graphql and Apollo?

More than that, when we do the update operation, it will be much more convenient. For example, modify a comment. We define a mutation operation of graphql

// ...

const updateComment = gql`
    mutation UpdateComment($id: Int!, $content: String!) {
      UpdateComment(id: $id, content: $content) {
        id
        content
        gmtModified
      }
    }
`;

class Comments extends React.Component {
    // ...
    onUpdateComment(id, content) {
        this.props.updateComment(id, content);
    }
    
    // ...
}

export default graphql(updateComment)(graphql(CommentsQuery)(Comments));

When we call updatecomment, you will find that the comment data in the list is automatically updated. This is because Apollo client automatically caches the data in the cache according to the type, and any data returned by the graphql node will be used to update the cache automatically. In the updatecomment mutation, we define its return value, a new modification comment of type comment, and specify the fields to be accepted,contentandgmtModified. In this way, Apollo client will automatically update the data in the cache by ID and type, thus re rendering our list.

Looking at the remaining requirements, we need to expand the user details when the mouse stays on the user’s Avatar. Under this requirement, we not only need to define what data we need, but also care about “how” to get the data (send the request when the hover avatar). Apollo also provides us with “imperative” support.

class UserItem extends React.Component {
    // ...
    onHover() {
        const { client, id } = this.props;
        
        client.query({
           query: UserQuery,
           variables: { id }
        }).then(data => {
            this.setState({ fullUserInfo: data });
        });
    }
}

export default withApollo(UserItem);

Fortunately, we still don’t have to think about caching. Thanks to Apollo’s global data cache, when we query user a, the data with the same ID will directly hit the cache, and Apollo client will directly resolve the data in the cache without sending a request. At this time, the question comes. Suppose I just want to re query every time?

client.query({
   query: UserQuery,
   variables: { id },
   fetchPolicy: 'cache-and-network'
});

Apollo provides us with a lot of strategies to define caching logic, such as the defaultcache-first(cache priority), here’s thecache-and-network(use cache first and send update request at the same time), andcache-onlyandnetwork-only

These are some of the things that appeal to me about graphql and Apollo. When you start to think from the perspective of graphql, you are more concerned with what data your business components need than how to get it step by step. Most of the remaining business scenarios can be solved automatically through the front-end data type derivation and caching. Of course, space is limited, there are many elegant places that can’t be mentioned, such as paging, direct operation cache, optimistic update, polling query, data subscription and so on. If we have a chance, we can continue to explore it in depth.

Rest and other local states?

Seeing this, you may think “graphql is very cool, Apollo is also very cool, but my back end is rest, so I have no chance with them at present.”. In fact, it is not. Since the introduction of Apollo link in version 2.0 of Apollo client, in theory, we can obtain data from any type of data source through graphql.

Still using Redux, do you want to try graphql and Apollo?

“Through graphql” means that we can use the query statements written in graphql to obtain the data in either the rest API or the client state, so that Apollo client can manage all the data in the application for us, including caching and data splicing.

const MIXED_QUERY = gql`
    query UserInfo() {
        // graphql endpoint
        currentUser {
            id
            name
        }
        // client state
        browserInfo @client {
            platform
        }
        // rest api
        messages @rest(route: '/user/messages') @type(type: '[Message]') {
            title
        }
    }
`;

In such a query, we use the directive of graphql to splice the data from graphql, rest and client state, and abstract them together for maintenance. Similarly, we can encapsulate the corresponding mutation implementation.

tail

The above is about my use of Apollo and graphql in this period of time. Although I don’t have deep contact, I can feel the more elegant solution brought by thinking in graphql for the front end, and the efficiency of a complete front-end data layer solution like Apollo client. I believe that in 2018, they will usher in greater growth, and even replace Redux as a general data management solution.

Apollo’s related communities are also quite activedev-blog.apollodata.comAlso often published on some of the articles of great reference value, interested can look at~