Is it possible to make a query which is dependent upon props?


#1

What did you do?

I’m building off of the create-cozy-app to learn how to use it. I’m trying to build a sort of list-of-lists based off of the original “to-do list” project. I have a sidebar which allows adding, removing, and navigating the lists, and I set up this router scheme to pass the list name from the sidebar through to the Todos component:

<Content className="app-content">
  <Switch>
    <Route path="/:todos" component={Todos} />
    <Redirect from="/" to="/todos" />
  </Switch>
</Content>

My doctypes folder is like so:

// ** in index.js ** //

import { ENTRIES_DOCTYPE } from './entries'
import { LISTS_DOCTYPE } from './lists'

// the documents schema, necessary for CozyClient
export default {
  entries: {
    doctype: ENTRIES_DOCTYPE,
    attributes: {},
    relationships: {
      list: {
        type: 'belongs-to-in-place',
        doctype: LISTS_DOCTYPE
      }
    }
  },
  lists: {
    doctype: LISTS_DOCTYPE,
    attributes: {},
    relationships: {
      entries: {
        type: 'has-many',
        doctype: ENTRIES_DOCTYPE
      }
    }
  }
}

// export all doctypes for the application
export * from './entries'
export * from './lists'


// ** In lists.js ** //

export const LISTS_DOCTYPE = 'tech.tams.todo-lists'

// query
export const listsQuery = client => client.find(LISTS_DOCTYPE)

// ** in entries.js **//

export const ENTRIES_DOCTYPE = 'tech.tams.entries'

// queries for CozyClient

export const entriesQuery = client => client.find(ENTRIES_DOCTYPE)

In the Todos component, I added const { listID } = props.routeParams to get the listID from the route, and I could filter directly in the component by something like entry.list.data.id === listID, but that would be hugely inefficient and require pulling down every entry from every list, then filtering it client-side for the right values every time a user switched lists. Ouch.

A potential solution

One potential solution is for the queryConnect function to optionally accept a function instead of an object. Then I could do a queryConnect statement like so:

export default queryConnect(props => ({
  todos: {
    query: entriesQuery.where({ 'list.id': props.routeParams.listID }),
    as: 'todos'
  }
}))(Todos)

Is there a solution that the current API offers that would have this effect?


#2

Hello @dscottboggs. Thanks for experimenting with create-cozy-app and cozy-client.

It is actually possible to make a query that depends on props, but for now it requires you to use the Query component inside your Todo component. Query uses the render prop (or render as a child) pattern, which you can read about in the React docs if you are not comfortable with this: https://reactjs.org/docs/render-props.html.

Still, the solution you propose at the end of your post is also a good idea I think, and I opened an issue on the cozy-client Github repo: https://github.com/cozy/cozy-client/issues/314. We will discuss it and eventually implement it. Thanks!


#3

@dscottboggs : after discussion with the team, what you want to achieve is actually already possible. It lacked some documentation, so we just added it. You can read about it here: https://github.com/cozy/cozy-client/blob/master/docs/how-tos.md#how-to-connect-to-multiple-queries-at-once-

This is not exactly the syntax you proposed, but it achieves the same goal :wink:


#4

Oh, that’s actually even better than what I suggested! Thanks so much!