Search code examples
reactjsgraphqlstoreapollo-client

React Apollo: Store updates after mutation but the ui does not reflect the change


I've created a graphQL server with following schema:

...
#charts interface
interface Chart {
  id: String!
  sql: String!
  title: String
  type: String!
  display: String!
}
type Layout{
  # Unique layout id
  id: String
  # The title displayed on the layout tab
  title: String
  # List of displayed charts
  charts: [Chart]
}
...

On my client I have a <SummaryLayout/> component with the following gql query:

gql`{
layout(id:"summary"){
  title
  charts {
    id,
    title,
    type,
    display
  }
}}`

When loading the page the layout component displays all the charts as a grid on the page. The user can later add a new chart, so I have 2 mutations: one creating the chart and the other is adding the new chart to the layout:

const addToLayout = gql`
mutation addToLayout($layoutID: String!, $chartID: String!) {
  addToLayout(layoutID: $layoutID ,chartID:$chartID){
    id
    charts {
      id
      sql
      title
      type
      display
    }
  }
}`;

const addChart = gql`
mutation addChart($chartConfig:ChartConfig!) {
  addChart(chartConfig:$chartConfig){
    id
    display
  }
}`;

this.props.addChart({
    variables: {chartConfig: chartConfig}
    }).then((response) => {
       const chartID = response.data.addChart.id;
       console.log("Chart added, DB ID:", chartID);
       this.props.addToLayout({
            variables: {layoutID: "summary", chartID: chartID},
            update: (store, data) => {
              console.log("STORE:",store);
            }
          }).then((response) => {
            appState.toggleDialog(false);
          })
     });

When I log the store I can see that the Layout:summary entry is updated, but it is not reflected at the UI, one more thing that popped is that there is another entry called $ROOT_QUERY.layout({"id":"summary"}) that is not updated with the new data:

enter image description here

What am I missing?


Solution

  • From the docs:

    By default, InMemoryCache will attempt to use the commonly found primary keys of id and _id for the unique identifier if they exist along with __typename on an object.

    If id and _id are not specified, or if __typename is not specified, InMemoryCache will fall back to the path to the object in the query, such as ROOT_QUERY.allPeople.0 for the first record returned on the allPeople root query. That would make data for given type scoped for allPeople query and other queries would have to fetch their own separate objects.

    Apollo uses that generated key to determine what to update when your mutation is resolved. What it boils down to is that both your queries and mutations need to include the id. This way the generated key used by both will be the same. In your code, it looks like the mutation includes the layout's id but the query does not.

    If for some reason, an id is not available, you can use the dataIdFromObject option to identify a different field to key off of.