psgmnd
psgmnd

Reputation: 83

How to combine two dependent GraphQL queries with 'compose'?

Solved!

I'm trying to combine two dependent GraphQL queries.

The first one should get an ID and the second one should take that ID. I read that compose behaves like flowRight(), but no matter in what order I put the queries, if queryId is below queryDetails, queryDetail's is always skipped (as expected). No matter how I put my code together the variable is undefined.

import { graphql, compose } from 'react-apollo'
import gql from 'graphql-tag'

class Home extends Component {
  constructor(props) {
    super(props)
    console.log("Where's my data?")
    console.log(props)
  }

  render() {
    return(
      <div />
    )
  }
}

export const queryIdConst = gql`
  query IdQuery {
    account(name:"SuperAccount") 
    {
      lists {
        edges {
          id
        }
      }
    } 
  }
`

export const queryDataConst = gql`
  query DataQuery($id: ID!) {
    account(name:"SuperAccount") 
    {
      list(id: $id) {
        displayTitle
      }
    } 
  }
`

export default compose(
  graphql(queryIdConst, {
    name: 'listId',
  }),
  graphql(queryDataConst, { 
    name: 'data',
    skip: ({ listId }) => !listId.data,
    options: ({ listId }) => ({
      variables: {
        id: list.data.account.lists.edges[0].id
      }
    })
  })
)(Home)

I have already tried to change the compose functions order, but anyway this is not working, as I expected it to work.

Thanks for any help!

Edit: Switched the two graphql() in compose() to be inline with AbsoluteSith's comment link

Solution

With hints and help from Daniel Rearden and AbsoluteSith I implemented the following solution:

Changed the compose():

export default compose(
  graphql(queryIdConst, {
    name: 'listId',
  }),
  graphql(queryDataConst, { 
    name: 'dataHome', // changed to 'dataHome' to avoid confusion
    skip: ({ listId }) => !listId.account,
    options: ({ listId }) => ({
      variables: {
        id: listId.account.lists.edges[0].id
      }
    })
  })
)(Home)

And my render():

return(
  <div>
    { dataHome && !dataHome.loading && 
      <div>{dataHome.account.list.displayTitle}</div> 
    }
  </div>
)

Upvotes: 8

Views: 6395

Answers (1)

Daniel Rearden
Daniel Rearden

Reputation: 84817

When using the graphql HOC, by default, the wrapped component receives a prop called data (or mutate if passing in a mutation). Given a query like

query IdQuery {
  account(name:"SuperAccount") {
    lists {
      edges {
        id
      }
    }
  } 
}

once the query loads, the query result is available under this.props.data.account. When you use the name configuration option, you're telling the HOC to use something other than data for the prop name. So if you set name to listId, then your query result will be available at

this.props.listId.account

That means the second HOC inside of compose should look more like this:

graphql(queryDataConst, { 
  skip: ({ listId }) => !listId.account, // <--
  options: ({ listId }) => ({
    variables: {
      id: listId.account.lists.edges[0].id // <--
    }
  })
})

Upvotes: 3

Related Questions