Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dispatch Redux action after React Apollo query returns

I'm using React Apollo to query all records in my datastore so I can create choices within a search filter.

The important database model I'm using is Report.

A Report has doorType, doorWidth, glass and manufacturer fields.

Currently when the query responds, I'm passing allReports to multiple dumb components which go through the array and just get the unique items to make a selectable list, like so..

const uniqueItems = []

items.map(i => {
  const current = i[itemType]

  if (typeof current === 'object') {
    if (uniqueItems.filter(o => o.id !== current.id)) {
      return uniqueItems.push(current)
    }
  } else if (!uniqueItems.includes(current)) {
    return uniqueItems.push(current)
  }

  return
})

Obviously this code isn't pretty and it's a bit overkill.

I'd like to dispatch an action when the query returns within my SidebarFilter components. Here is the query...

const withData = graphql(REPORT_FILTER_QUERY, {
  options: ({ isPublished }) => ({
    variables: { isPublished }
  })
})

const mapStateToProps = ({
  reportFilter: { isPublished }
  // filterOptions: { doorWidths }
}) => ({
  isAssessment
  // doorWidths
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      resetFilter,
      saveFilter,
      setDoorWidths,
      handleDoorWidthSelect
    },
    dispatch
  )

export default compose(connect(mapStateToProps, mapDispatchToProps), withData)(
  Filter
)

The Redux action setDoorWidths basically does the code above in the SidebarFilter component but it's kept in the store so I don't need to re-run the query should the user come back to the page.

It's very rare the data will update and the sidebar needs to change.

Hopefully there is a solution using the props argument to the graphql function. I feel like the data could be taken from ownProps and then an action could be dispatched here but the data could error or be loading, and that would break rendering.

Edit:

Query:

query ($isPublished: Boolean!){
  allReports(filter:{
    isPublished: $isPublished
  }) {
  id
  oldId
  dbrw
  core
  manufacturer {
    id
    name
  }
  doorWidth
  doorType
  glass
  testBy
  testDate
  testId
  isAssessment
  file {
    url
  }
  }
}
like image 786
Jamie B Avatar asked Jul 21 '17 11:07

Jamie B


2 Answers

While this answer addresses the specific issue of the question, the more general question -- where to dispatch a Redux action based on the result of a query -- remains unclear. There does not, as yet, seem to be a best practice here.

like image 119
Adam Donahue Avatar answered Sep 30 '22 16:09

Adam Donahue


It seems to me that, since Apollo already caches the query results in your store for you (or a separate store, if you didn't integrate them), it would be redundant to dispatch an action that would also just store the data in your store.

If I understood your question correctly, your intent is to filter the incoming data only once and then send the result down as a prop to the component's stateless children. You were on the right track with using the props property in the graphql HOC's config. Why not just do something like this:

const mapDataToProps = ({ data = {} }) => {
  const items = data
  const uniqueItems = []

  // insert your logic for filtering the data here

  return { uniqueItems } // or whatever you want the prop to be called
}

const withData = graphql(REPORT_FILTER_QUERY, {
  options: ({ isPublished }) => ({
    variables: { isPublished }
  }),
  props: mapDataToProps,
})

The above may need to be modified depending on what the structure of data actually looks like. data has some handy props on it that can let you check for whether the query is loading (data.loading) or has errors (data.error). The above example already guards against sending an undefined prop down to your children, but you could easily incorporate those properties into your logic if you so desired.

like image 45
Daniel Rearden Avatar answered Sep 30 '22 16:09

Daniel Rearden