Syncing State with Location
As the final step of this unit, we'll be learning how to sync the state of our tables with the location. This will allow us to share the current state of the table with others. For example, we can share the URL of the table with our colleagues and they will see the same table with the same filters, sorting, and pagination.
Refine's useTable
hook offers a syncWithLocation
option that allows us to sync the state of the table with the location with a single line of code.
Whenever the state of the table changes (e.g. filters, sorting, pagination), the URL will be updated with the new state. And the table will be updated with the state in the URL when the page is loaded.
Let's update our <ListProducts>
component and add the syncWithLocation
option to the useTable
hook.
Update your src/pages/products/list.tsx
file by adding the following lines:
import { useTable, useMany, useNavigation } from "@refinedev/core";
export const ListProducts = () => {
const {
tableQuery: { data, isLoading },
current,
setCurrent,
pageCount,
sorters,
setSorters,
} = useTable({
pagination: { current: 1, pageSize: 10 },
sorters: { initial: [{ field: "id", order: "asc" }] },
syncWithLocation: true,
});
/* ... */
};
Now, let's try to navigate to the /products
page and change the filters, sorting, or pagination. You'll see that the URL is updated with the new state of the table. When you refresh the page, you'll see that the table is updated with the same state in the URL.
Summary
In this unit, we've learned;
- How to use Refine's router integrations,
- How to define resources and why it's important to define them,
- Using the inferred parameters from the URL in our hooks,
- Using Refine's hooks to handle navigation between any action of any resource,
- Handling redirections from auth provider and forms,
- Syncing the state of the table with the location.
In the next unit, we'll be learning on how to use a UI framework with Refine and how Refine handles the UI framework integrations.
import { AuthProvider } from "@refinedev/core"; export const authProvider: AuthProvider = { onError: async (error) => { if (error?.status === 401) { return { logout: true, error: { message: "Unauthorized" }, }; } return {}; }, getIdentity: async () => { const response = await fetch("https://api.fake-rest.refine.dev/auth/me", { headers: { Authorization: localStorage.getItem("my_access_token"), }, }); if (response.status < 200 || response.status > 299) { return null; } const data = await response.json(); return data; }, logout: async () => { localStorage.removeItem("my_access_token"); return { success: true, redirectTo: "/login" }; }, // login method receives an object with all the values you've provided to the useLogin hook. login: async ({ email, password }) => { const response = await fetch( "https://api.fake-rest.refine.dev/auth/login", { method: "POST", body: JSON.stringify({ email, password }), headers: { "Content-Type": "application/json", }, }, ); const data = await response.json(); if (data.token) { localStorage.setItem("my_access_token", data.token); return { success: true, redirectTo: "/" }; } return { success: false }; }, check: async () => { const token = localStorage.getItem("my_access_token"); return { authenticated: Boolean(token) }; }, // optional methods register: async (params) => { throw new Error("Not implemented"); }, forgotPassword: async (params) => { throw new Error("Not implemented"); }, updatePassword: async (params) => { throw new Error("Not implemented"); }, getPermissions: async () => { throw new Error("Not implemented"); }, };
![](/assets/tutorial-spinner.gif)