5. Advanced example
Now that we have seen a basic example it is time to show some more advanced examples.
Note: all examples below will use useQueryParams
, but they are
all possible with withQueryParams
as well.
5.1 Handling changing query params
Here’s an example showing you how to trigger a change in query params.
The important parts are the queryChanged
function which is called when the input
element changes, and the pageChanged
function which is called when
going to the next page.
// Dashboard.tsx
import React from 'react';
import { useHistory, useLocation, useParams } from 'react-router';
import { Url, useQueryParams, urlBuilder } from '@42.nl/react-url';
type DashboardPathParams = {
id: string;
}
type DashboardQueryParams = {
page: number;
query: string;
}
export function defaultDashboardQueryParams(): DashboardQueryParams {
return {
page: 1,
query: '',
};
}
type Props = {};
export default function Dashboard(props: Props) {
const { id } = useParams<DashboardPathParams>();
const location = useLocation();
const history = useHistory();
const queryParams = useQueryParams({
location,
defaultQueryParams: defaultDashboardQueryParams(),
debugName: 'Dashboard',
});
/*
queryChanged re-navigates to the same url with a search query
which restarts the page to 1.
*/
function queryChanged(query: string) {
history.push(
/*
Keep the id as is in the path, but change the query params
and change the search `query`. By not adding the `page` it
will be reset to 1.
*/
toDashboard({ id }, { query }),
);
}
/*
pageChanged re-navigates to the same url with a changed page
but with the same query as before
*/
function pageChanged(page: number) {
history.push(
/*
Keep the id as is in the path, but change the page and
keep the original search query. This is done by creating
a copy from the old query params via the `...` operator.
*/
toDashboard({ id }, { ...queryParams, page }),
);
}
const { query, page } = queryParams;
return (
<div>
<input type="text" value={query} onChange={event => queryChanged(event.target.value)} />
<button onClick={() => pageChanged(page - 1)}>Prev</button>
{page}
<button onClick={() => pageChanged(page + 1)}>Next</button>
</div>
);
}
export const DASHBOARD_URL = '/dashboard/:id';
export function toDashboard(pathParams: DashboardPathParams, queryParams?: Partial<DashboardQueryParams>): Url {
return urlBuilder({
url: DASHBOARD_URL,
pathParams,
queryParams,
defaultQueryParams: defaultDashboardQueryParams(),
});
}
The trick is simple: whenever you want to change the query params simply call url function again.
5.2 Fetching data based on path variables and query params
This example show you how you can load data from the back-end based on the query params and path params. The trick here is to fetch data from the back-end each time the query params or path params change.
The example uses @42.nl/spring-connect to fetch the user from the back-end, and react-async to handle the loading state.
import React from 'react';
import { Url, urlBuilder, useQueryParams } from '@42.nl/react-url';
import { useAsync } from 'react-async';
import { useHistory, useLocation, useParams } from 'react-router';
/* User is a @42.nl/spring-connect Resource */
import User from 'User';
export type UserEditPathParams = {
id: string;
}
export type UserEditQueryParams = {
active: boolean;
}
export function defaultUserEditQueryParams(): UserEditQueryParams {
return {
active: false,
};
}
type Props = {};
export function loadUser(
{ id, queryParams }:
{ id: string; queryParams: UserEditQueryParams }
): Promise<User> {
return User.one(id, queryParams);
}
export default function UserEdit(props: Props) {
const { id } = useParams<DashboardPathParams>();
const location = useLocation();
const queryParams = useQueryParams({
location,
defaultQueryParams: defaultUserEditQueryParams(),
debugName: 'UserEdit',
});
/*
Calls `loadUsers each time the query params or path params have
changed. This is achieved by setting the `watch`.
*/
const { data, isLoading } = useAsync(loadUser, { id, queryParams, watch: `${id}${queryParams.active}` });
if (isLoading && !data) {
return <h1>Loading...</h1>;
}
const user = data as User;
return <h1>Hey you are editing: {user.name}</h1>;
}
export const USER_EDIT_URL = '/users/:id/edit';
export function toUserEdit(pathParams: UserEditPathParams, queryParams?: Partial<UserEditQueryParams>): Url {
return urlBuilder({
url: USER_EDIT_URL,
pathParams,
queryParams,
defaultQueryParams: defaultUserEditQueryParams(),
});
}