DEV Community

Ian Jones
Ian Jones

Posted on

Make a GraphQL Query Dynamic with Variables and Urqls useQuery Hook

Watch "Pass Parameters to urql's useQuery React Hook" (free community resource) on egghead.

We have this GraphQL Query:

const courseQuery = `
  query courses {
    courses {
      title
    }
  }
`

To pass a parameter to a graphql query, we will add (limit: 2) to courses.

const courseQuery = `
  query courses {
    courses(limit: 2) {
      title
    }
  }
`

This parameter will limit the number of courses that come back. Next we are going to pass an offset to this query. Offset is 0 based so we will pass get our first page of courses with 0.

const courseQuery = `
  query courses {
    courses(limit: 2, offset: 0) {
      title
    }
  }
`

Incrementing offset to 1 will give use the next page of courses and so on. We dont want to hard code our query like this though. We need to pass a variable from our React component to our GraphQL query. Just as a reminder, here's what our component looks like right now:

function App() {
  const [result] = useQuery({
    query: courseQuery,
  })

  if (result.fetching) {
    return 'Loading...'
  } else if (result.error) {
    return 'There was an error :('
  }

  return (
    <div>
      <h1>egghead courses</h1>
      <button onClick={() => setOffset(offset + 2)}>Next Page</button>
      {result && result.data && (
        <ul style={{ listStyle: 'none' }}>
          {result.data.courses.map(({ title }) => (
            <li
              key={title}
              style={{
                display: 'flex',
                alignItems: 'center',
                fontSize: 16,
                fontFamily: 'sans-serif',
                marginBottom: 10,
              }}
            >
              {title}
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}

The first thing we need to do is update our coursesQuery to accept a variable. We will declare an $offset: Int variable in our query declaration. GraphQL query variables are always denoted with a $. They also always need to be assigned a type. In this case, we are using an integer (Int is the syntax).

const courseQuery = `
  query courses($offset: Int) {
  }
`

Now that we have a parameter of $offset declared, we are going to pass this parameter to our query with courses(offset: $offset).

const courseQuery = `
  query courses($offset: Int) {
    courses(offset: $offset, limit: 2) {
      title
    }
  }
`

Inside of our component, we need to pass a variables object with a key of offset to our useQuery hook.

const [result] = useQuery({
  query: courseQuery,
  variables: {
    offset: 0,
  },
})

Urql will handle running the query for us every time this offset variable changes. So if we create some local component state and pass that state to our useQuery hook, any time this variable is updated Urql will run our query.

const [offset, setOffset] = React.useState(0)
const [result] = useQuery({
  query: courseQuery,
  variables: {
    offset,
  },
})

Now lets increment the offset every time someone clicks our Next Page button.

return (
    <div>
      <h1>egghead courses</h1>
      <button onClick={() => setOffset(offset + 1)}>Next Page</button>
      {result && result.data && (
        //...
      )}
    </div>
  )

And thats it! now we have pagination set up with a couple simple hooks.

Top comments (0)