Skip to content

Commit

Permalink
Add useRoute hook for typesafe route params (#1284)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlecAivazis committed Mar 11, 2024
1 parent 250ff78 commit d69d172
Show file tree
Hide file tree
Showing 23 changed files with 550 additions and 209 deletions.
5 changes: 5 additions & 0 deletions .changeset/poor-stingrays-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'houdini-react': patch
---

Add useRoute prop for typesafe route parameters
8 changes: 7 additions & 1 deletion e2e/react/src/routes/route_params/[id]/+page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { useRoute } from '$houdini'

import type { PageProps } from './$types'

export default function ({ RouteParamsUserInfo }: PageProps) {
const route = useRoute<PageProps>()

const { user } = RouteParamsUserInfo
return (
<div>
<div>{user.name}</div>
<div>
{route.params.id}: {user.name}
</div>
</div>
)
}
4 changes: 2 additions & 2 deletions e2e/react/src/routes/route_params/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ test('Component fields with correct argument value', async ({ page }) => {
await goto(page, routes.route_params)

// be default we see user 1
await expect_to_be(page, 'Bruce Willis')
await expect_to_be(page, '1:Bruce Willis')

// click on the link 2
await page.click('user-link-2')
Expand All @@ -16,5 +16,5 @@ test('Component fields with correct argument value', async ({ page }) => {
await sleep(100)

// make sure we loaded the second user's information
await expect_to_be(page, 'Samuel Jackson')
await expect_to_be(page, '2:Samuel Jackson')
})
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async function generate_query_wrapper(args: PageBundleInput) {

// build up the file source as a string
let source: string[] = [
"import { useQueryResult } from '$houdini/plugins/houdini-react/runtime/routing'",
"import { useQueryResult, PageContextProvider } from '$houdini/plugins/houdini-react/runtime/routing'",
`import ${component_name} from "${relative_path}"`,
]

Expand All @@ -96,15 +96,17 @@ async function generate_query_wrapper(args: PageBundleInput) {
.join('\n')}
return (
<${component_name}
${page.queries
.map((query) =>
[`${query}={${query}$data}`, `${query}$handle={${query}$handle}`].join(' ')
)
.join('\n')}
>
{children}
</${component_name}>
<PageContextProvider keys={${JSON.stringify(Object.keys(page.params ?? {}))}}>
<${component_name}
${page.queries
.map((query) =>
[`${query}={${query}$data}`, `${query}$handle={${query}$handle}`].join(' ')
)
.join('\n')}
>
{children}
</${component_name}>
</PageContextProvider>
)
}`)

Expand Down
84 changes: 68 additions & 16 deletions packages/houdini-react/src/plugin/codegen/entries/entries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ test('composes layouts and pages', async function () {
}
)
expect(page_unit).toMatchInlineSnapshot(`
import { useQueryResult } from "$houdini/plugins/houdini-react/runtime/routing";
import { useQueryResult, PageContextProvider } from "$houdini/plugins/houdini-react/runtime/routing";
import Component__subRoute_nested from "../../../../../src/routes/subRoute/nested/+page";
export default (
Expand All @@ -82,9 +82,11 @@ test('composes layouts and pages', async function () {
const [FinalQuery$data, FinalQuery$handle] = useQueryResult("FinalQuery");
return (
(<Component__subRoute_nested FinalQuery={FinalQuery$data} FinalQuery$handle={FinalQuery$handle}>
{children}
</Component__subRoute_nested>)
(<PageContextProvider keys={[]}>
<Component__subRoute_nested FinalQuery={FinalQuery$data} FinalQuery$handle={FinalQuery$handle}>
{children}
</Component__subRoute_nested>
</PageContextProvider>)
);
};
`)
Expand All @@ -98,7 +100,7 @@ test('composes layouts and pages', async function () {
}
)
expect(root_layout_unit).toMatchInlineSnapshot(`
import { useQueryResult } from "$houdini/plugins/houdini-react/runtime/routing";
import { useQueryResult, PageContextProvider } from "$houdini/plugins/houdini-react/runtime/routing";
import Component__ from "../../../../../src/routes/+layout";
export default (
Expand All @@ -107,9 +109,11 @@ test('composes layouts and pages', async function () {
}
) => {
return (
(<Component__>
{children}
</Component__>)
(<PageContextProvider keys={[]}>
<Component__>
{children}
</Component__>
</PageContextProvider>)
);
};
`)
Expand All @@ -123,7 +127,7 @@ test('composes layouts and pages', async function () {
}
)
expect(deep_layout_unit).toMatchInlineSnapshot(`
import { useQueryResult } from "$houdini/plugins/houdini-react/runtime/routing";
import { useQueryResult, PageContextProvider } from "$houdini/plugins/houdini-react/runtime/routing";
import Component__subRoute from "../../../../../src/routes/subRoute/+layout";
export default (
Expand All @@ -135,13 +139,15 @@ test('composes layouts and pages', async function () {
const [SubQuery$data, SubQuery$handle] = useQueryResult("SubQuery");
return (
(<Component__subRoute
RootQuery={RootQuery$data}
RootQuery$handle={RootQuery$handle}
SubQuery={SubQuery$data}
SubQuery$handle={SubQuery$handle}>
{children}
</Component__subRoute>)
(<PageContextProvider keys={[]}>
<Component__subRoute
RootQuery={RootQuery$data}
RootQuery$handle={RootQuery$handle}
SubQuery={SubQuery$data}
SubQuery$handle={SubQuery$handle}>
{children}
</Component__subRoute>
</PageContextProvider>)
);
};
`)
Expand Down Expand Up @@ -254,6 +260,52 @@ test('composes layouts and pages', async function () {
`)
})

test('layout with params', async function () {
const config = await test_config()

// create the mock filesystem
await fs.mock({
[config.routesDir]: {
'[id]': {
'+page.gql': 'query RootQuery($id: ID!) { node(id: $id) { id } }',
'+page.tsx': 'export default function({ RootQuery}) { return "hello" }',
},
},
})
// generate the manifest
const manifest = await load_manifest({ config })

// generate the bundle for the nested page
await generate_entries({ config, manifest, documents: [], componentFields: [] })

const page_entry = await parseJS(
(await fs.readFile(
routerConventions.page_unit_path(config, Object.keys(manifest.pages)[0])
)) ?? '',
{ plugins: ['jsx'] }
)
expect(page_entry).toMatchInlineSnapshot(`
import { useQueryResult, PageContextProvider } from "$houdini/plugins/houdini-react/runtime/routing";
import Component___id_ from "../../../../../src/routes/[id]/+page";
export default (
{
children
}
) => {
const [RootQuery$data, RootQuery$handle] = useQueryResult("RootQuery");
return (
(<PageContextProvider keys={["id"]}>
<Component___id_ RootQuery={RootQuery$data} RootQuery$handle={RootQuery$handle}>
{children}
</Component___id_>
</PageContextProvider>)
);
};
`)
})

function mockView(deps: string[]) {
return `export default ({ ${deps.join(', ')} }) => <div>hello</div>`
}
Expand Down
32 changes: 16 additions & 16 deletions packages/houdini-react/src/plugin/codegen/router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ test('happy path', async function () {
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: false,
variables: []
variables: {}
}
},
Expand All @@ -70,12 +70,12 @@ test('happy path', async function () {
SubQuery: {
artifact: () => import(\\"../../../artifacts/SubQuery\\"),
loading: false,
variables: []
variables: {}
},
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: false,
variables: []
variables: {}
}
},
Expand All @@ -92,17 +92,17 @@ test('happy path', async function () {
MyQuery: {
artifact: () => import(\\"../../../artifacts/MyQuery\\"),
loading: false,
variables: []
variables: {}
},
MyLayoutQuery: {
artifact: () => import(\\"../../../artifacts/MyLayoutQuery\\"),
loading: true,
variables: []
variables: {}
},
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: false,
variables: []
variables: {}
}
},
Expand All @@ -119,12 +119,12 @@ test('happy path', async function () {
FinalQuery: {
artifact: () => import(\\"../../../artifacts/FinalQuery\\"),
loading: true,
variables: [\\"foo\\"]
variables: {\\"foo\\":{\\"wrappers\\":[\\"Nullable\\"],\\"type\\":\\"Int\\"}}
},
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: false,
variables: []
variables: {}
}
},
Expand Down Expand Up @@ -198,7 +198,7 @@ test('loading state at root', async function () {
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: true,
variables: []
variables: {}
}
},
Expand All @@ -215,12 +215,12 @@ test('loading state at root', async function () {
SubQuery: {
artifact: () => import(\\"../../../artifacts/SubQuery\\"),
loading: false,
variables: []
variables: {}
},
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: true,
variables: []
variables: {}
}
},
Expand All @@ -237,17 +237,17 @@ test('loading state at root', async function () {
MyQuery: {
artifact: () => import(\\"../../../artifacts/MyQuery\\"),
loading: false,
variables: []
variables: {}
},
MyLayoutQuery: {
artifact: () => import(\\"../../../artifacts/MyLayoutQuery\\"),
loading: false,
variables: []
variables: {}
},
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: true,
variables: []
variables: {}
}
},
Expand All @@ -264,12 +264,12 @@ test('loading state at root', async function () {
FinalQuery: {
artifact: () => import(\\"../../../artifacts/FinalQuery\\"),
loading: false,
variables: []
variables: {}
},
RootQuery: {
artifact: () => import(\\"../../../artifacts/RootQuery\\"),
loading: true,
variables: []
variables: {}
}
},
Expand Down
Loading

0 comments on commit d69d172

Please sign in to comment.