Apollo Normalization with dataIdFromObject not updating

1k Views Asked by At

I am having trouble with getting React+Apollo to update the store after I send a delete mutation. I am using the reactQL boiler plate which has apollo+react built in and an express graphQL server (I didn't install the apollo server- I just use the reference express-graphQL package). My data is stored in the mongoDB with a _id, but the actual data on the client side uses id as the id.

The apollo client is defined like this:

new ApolloClient(
    Object.assign(
      {
        reduxRootSelector: state => state.apollo,
        dataIdFromObject: o => o.id
      },
      opt
    )
  );

I have a parent component which uses import courses from 'src/graphql/queries/courses.gql

@graphql(courses)
export default class CoursesPage extends Component {
  constructor(props){
    super(props)
    this.handleDelete = this.handleDelete.bind(this);
  }

  handleDelete(event) {
    this.props.mutate({ variables: {id: selectedId}}
              .catch(err => console.log(err))
  }

  render() {
    return (
      { this.props.data.courses.map(course =>
         <CourseDelete selectedId={course.id} key={course.id} />
        })
      }
    )
  }

}

and a child component that looks like:

import deleteCoursefrom 'src/graphql/mutations/deleteCourse.gql

@graphql(deleteCourse)
export default class CourseDelete extends Component {
  constructor(props){
    super(props)
    this.handleDelete = this.handleDelete.bind(this);
  }

  handleDelete(event) {
    this.props.mutate({ variables: {id: this.props.selectedId}}
              .catch(err => console.log(err))
  }

  render() {
    return (
      <button onClick={this.handleDelete}>Button</button>
    )
  }

}

where deleteCourse.gql:

mutation deleteCourse($id: String!) {
  deleteCourse(id: $id) {
    id
  }
}

and my original query is in courses.gql:

query courses {
  courses {
    id
  }
}
1

There are 1 best solutions below

1
On BEST ANSWER

Apollo's dataIdFromObject is used to update objects already in the cache. So if you have a record and an ID, and you change other pieces of data against that same ID, React components listening to the store can can re-render.

Since your deleteCourse mutation seems to return the same ID, it still exists in the cache. Your store doesn't know it needs deleting- it just updates the cache with whatever data comes back. Since this mutation likely returns the same ID, there's nothing to signify that this should be removed.

Instead, you need to specify an update function (link goes to the official Apollo docs) to explicitly delete the underlying store data.

In my new ReactQL user auth example, I do the same thing (see the pertinent LOC here) to 'manually' update the store after a user logs in.

Since components are initially listening to a 'blank' user, I cannot rely on dataObjectFromId to invalidate the cache, since I'm starting with no users and therefore no IDs. So I explicitly overwrite store state manually, which triggers re-rendering of any listening components.

I explain the concept is the context of the above user auth in a YouTube video - this is the piece that's relevant: https://youtu.be/s1p4R4rzWUs?t=21m12s