Skip to content

Loading Data

Just like views are defined in page and layout variants, your applications queries are defined in +page.gql and +layout.gql files. Queries must have a unique name:

src/routes/shows/+page.gql
query ShowList {
shows {
title
}
}

Just like their equivalent view component, layout queries are designed to “wrap” child routes and are accessible by any child (or sibling) page or layout component.

To access the value of a query, your component just needs to accept a prop with the appropriate name. This could be one query or as many as you have defined. Keep in mind that since this works off of very simple static analysis, your component props must be spread out from the argument like so:

src/routes/shows/+page.tsx
export default function ({ ShowList }) {
return (
<>
{ShowList.shows.map(show => (
<div>
{show.title}
</div>
))}
</>
)
}
src/routes/shows/+page.jsx
export default function ({ ShowList }) {
return (<>
{ShowList.shows.map(show => (<div>
{show.title}
</div>))}
</>)
}

An arrow function would have also worked as long as it had { ShowList } or { ShowList, AnotherQuery }

Query Variables

If your query contains variables with the same name as a route parameter, Houdini will wire the two up.

For example, all you need to do is define this query at src/routes/show/[id]/+page.gql and you can visit /show/123 or /show/abc:

src/routes/show/[id]/+page.gql
query ShowInfo($id: ID!) {
show(id: $id) {
name
}
}

Runtime Scalars

An unforunate reality is that not all query variables can be embeded as route paramters. A common example of this is information that’s embedded in your application’s session. To support this, we are working on an experimental API known as Runtime Scalars.

Runtime Scalars

To enable and configure this feature, you must provide an object to the runtimeScalars feature config:

houdini.config.js
export default {
// ...
features: {
runtimeScalars: {
OrganizationFromSession: {
type: 'ID',
resolve: ({session}) => session.organization
}
}
}
}

With that defined, you can now use it as a scalar in a query and Houdini will call the configured resolve function to generate the variable value:

+page.gql
query OrganizationInfo($id: OrganizationFromSession!) {
organization(id: $id) {
name
}
}

Please keep in mind that this feature is still considered experimental and could change with any minor version.

Imperative Handles

Sometimes you need to perform some imperative task on a query (refetching, loading the next page, etc). For these situations, you should use the $handle variant on the query prop. For example:

src/routes/shows/+page.tsx
export default function ({ ShowList$handle }) {
return (
<>
<button onClick={ShowList$handle.loadNextPage}>
Load Next
</button>
{ShowList.shows.map(show => (
<div>
{show.title}
</div>
))}
</>
)
}
src/routes/shows/+page.jsx
export default function ({ ShowList$handle }) {
return (<>
<button onClick={ShowList$handle.loadNextPage}>
Load Next
</button>
{ShowList.shows.map(show => (<div>
{show.title}
</div>))}
</>)
}

Loading States

Loading states are one of Houdini’s most powerful features. Apart from one important difference, all of the information in the guide on loading states applies to the react framework. Hopefully you didn’t just click that link because it’s important to remember that you have to use isPending from the $houdini package when identifying a pending value. What you see in that guide (checking if === PendingValue) won’t work with React 18.2.

Another thing to keep in mind is that for the React framework, the presence of @loading implies the existence of a suspense boundary in your component hierarchy. I know that last sentence might not be totally clear but explaining it more thoroughly will take time so please be patient.