Ivo
Ivo

Reputation: 2510

Apollo / GraphQl - Single entity mutation does not update cache (database updated)

I'm facing an issue with the integration of apollo / graphql into a new project.

I have a component, BrandsList, that lists brand. From this component you can click on a Brand to reach an updateForm for each brand to update its information.

Here is the update form:

import React, { useState, useEffect } from "react";
import { graphql } from "react-apollo";
import gql from "graphql-tag";
import { UPDATE_BRAND } from "./../../../api/brands/mutations";
import { Form, Button, Dropdown, TextArea } from "semantic-ui-react";
import { useQuery, useMutation } from "@apollo/react-hooks";

const brandQuery = gql`
    query Brand($brandId: String) {
        brand(_id: $brandId) {
            _id
            name
            url
            description
            brandType
            openingDate
            closingDate
            origin
            region
            address
        }
    }
`;

const UpdateBrand = props => {
    const [values, setValues] = useState({
        _id: "",
        name: "",
        url: "",
        description: "",
        origin: "",
        region: "",
        brandType: "",
        openingDate: "",
        closingDate: "",
        address: ""
    });

    const onChange = e => {
        const { name, value } = e.target;
        setValues({ ...values, [name]: value });
    };

    const { loading, error, data, refetch } = useQuery(brandQuery, {
        variables: { brandId: props.match.params.brandId }
    });

    useEffect(() => {
        if (data) {
            setValues({ ...data.brand });
        }
    }, [data]);

    const [updateBrand, { brand }] = useMutation(UPDATE_BRAND);

    const onChangeDropDown = (e, { value }) =>
        setValues({ ...values, brandType: value });

    const onSubmit = e => {
        e.preventDefault();
        let {
            _id,
            name,
            url,
            description,
            origin,
            region,
            brandType,
            openingDate,
            closingDate,
            address
        } = values;

        updateBrand({
            variables: {
                brandId: _id,
                name,
                url,
                description,
                origin,
                region,
                brandType,
                openingDate,
                closingDate,
                address
            }
        })
        .then(() => props.history.push("/admin/brands"))
        .catch(err => console.log(err));

    };


    return (
        <div className="createBrand">
            <h1>Add a Brand</h1>
            /* BORING STATE CONTROLLED FORM  */
                <Button type="submit" form="createBrandForm">
                    Update
                </Button>
            </Form>
        </div>
    );
};

export default UpdateBrand;

Generally it's working well, not sure if using useEffect to bring the query result in my local state is the most efficient but it works. I can modify my form and resubmit it and data are changed in the database. However when I am brought back to /admin/brands thanks to props.history.push the data is not updated and I have to do a hard refresh.

My Mutation resolver is as such :

updateBrand(obj, args, context) {
    if (!context.user || !context.user.isAdmin) {
        throw new Error("You have to be an admin to update a brand");
    } else if (context.user.isAdmin) {
        let {
            brandId,
            name,
            url,
            description,
            origin,
            region,
            brandType,
            openingDate,
            closingDate,
            address
        } = args;
        Brands.update(
            { _id: brandId },
            {
                $set: {
                    name,
                    url,
                    description,
                    origin,
                    region,
                    brandType,
                    openingDate,
                    closingDate,
                    address
                }
            }
        );
        return Brands.findOne({ _id: brandId });
    }
},

So as per documentation I am returning the updated single object that should force an update of the cache for the modification of a single entity. However it is not the case. Any ideas on how to have a fresh update of data after each modification ?

Here is the mutation code:

export const UPDATE_BRAND = gql`
    mutation updateBrand(
        $brandId: String!
        $name: String!
        $url: String
        $description: String
        $origin: String
        $region: String
        $brandType: String
        $openingDate: String
        $closingDate: String
        $address: String
    ) {
        updateBrand(
            brandId: $brandId
            name: $name
            url: $url
            description: $description
            origin: $origin
            region: $region
            brandType: $brandType
            openingDate: $openingDate
            closingDate: $closingDate
            address: $address
        ) {
            _id
        }
    }
`;

and here the Schema part :

type Mutation {
    createBrand(
        name: String!
        url: String
        description: String
        origin: String
        region: String
        brandType: String
        openingDate: String
        closingDate: String
        address: String
    ): Brand
    updateBrand(
        brandId: String!
        name: String!
        url: String
        description: String
        origin: String
        region: String
        brandType: String
        openingDate: String
        closingDate: String
        address: String
    ): Brand
    deleteBrand(brandId: String!): Boolean
}

Upvotes: 2

Views: 3845

Answers (2)

Ivo
Ivo

Reputation: 2510

My mistake was in my graphQL query code for the update mutation as suggested by @Herku. I was only sending back the _id after the update and not the rest of the data. Changing to the following solved the issue :

export const UPDATE_BRAND = gql`
    mutation updateBrand(
        $brandId: String!
        $name: String!
        $url: String
        $description: String
        $origin: String
        $region: String
        $brandType: String
        $openingDate: String
        $closingDate: String
        $address: String
    ) {
        updateBrand(
            brandId: $brandId
            name: $name
            url: $url
            description: $description
            origin: $origin
            region: $region
            brandType: $brandType
            openingDate: $openingDate
            closingDate: $closingDate
            address: $address
        ) {
            _id
            name
            url
            description
            origin
            region
            brandType
            openingDate
            closingDate
            address
        }
    }
`;

Upvotes: 3

Loren
Loren

Reputation: 14836

The list query has to be updated manually:

https://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updates

Upvotes: 0

Related Questions