javascriptreactjsreact-apollonext.jsoptimistic-ui

Apollo/graphQL: How to use optimistic UI for a mutation of a nested react component?


As shown below I'm getting my data in my nextJS application in the pages/article.js using a graphQL query. This data is passed down to another react component, which gives me a list of checkboxes.

Selecting a checkbox is calling a mutation to store the ID of the selected checkboxes in the DB. To get the content updated, I'm using refetchQueries to call the main query again, which will pass the data down to the current component.

So far everything is working. Now I would like to get this stuff realtime using optimistic UI - which makes me some problems...

Replacing the refetchQueries with

update: (store, { data: { getArticle } }) => {
  const data = store.readQuery({
    query: getArticle,
    variables: {
      id: mainID
    }
  })
  console.log(data)
}

runs me to the error TypeError: Cannot read property 'kind' of undefined which comes from readQuery.

I don't see what I'm doing wrong. And this is just the first part to get optimisic UI..

pages/article.js

import Article from '../components/Article'

class ArticlePage extends Component {
  static async getInitialProps (context, apolloClient) {
    const { query: { id }, req } = context
    const initProps = { }

    // ...

    return { id, ...initProps }
  }

  render () {
    const { id, data } = this.props
    const { list } = data
    return (
      <Article
        mainID={id}
        list={list}
      />
    )
  }
}

export default compose(
  withData,
  graphql(getArticle, {
    options: props => ({
      variables: {
        id: props.id
      }
    })
  })
)(ExtendedArticlePage)

components/Article.js

import { getArticle } from '../graphql/article'
import { selectMutation } from '../graphql/selection'

export class Article extends Component {
  checkboxToggle (id) {
    const { mainID, checkboxSelect } = this.props

    checkboxSelect({
      variables: {
        id
      },
      refetchQueries: [{
        query: getArticle,
        variables: {
          id: mainID
        }
      }],

    })
  }

  render () {
    const { list } = this.props
    return (
      list.map(l => {
        return (<Checkbox onClick={this.checkboxToggle.bind(this, l.id)} label={l.content} />)
      }
    )
  }
}

export default compose(
  graphql(selectMutation, { name: 'checkboxSelect' })
)(Article)

Solution

  • You have a variable shadowing issue in your update code, it seems that you're using the same name getArticle for both your query and the mutation result nested in data.

    This is why your call to readQuery fails, the query params you need to provide resolves to the mutation result and not the actual query, hence the TypeError: Cannot read property 'kind' of undefined.

    You just need to name your query with another identifier like getQueryArticle.