Skip to main content

Inferring Parameters

Now we've learned about the useNavigation hook and how to handle navigation with Refine. In this step, we'll be updating components to benefit from the parameter inference of Refine.

When integrated with a router provider, Refine infers the parameters from route definitions and incorporates them into its hooks and components, eliminating the need for manual passing of resource, id and action parameters.

TIP

You can always pass the parameters manually if you want to override the inferred parameters.

Updating the ListProducts Component

Let's update our <ListProducts /> component and omit the resource parameter from the useTable hook.

Update your src/pages/products/list.tsx file by adding the following lines:

src/pages/products/list.tsx
import { useTable, useMany } from "@refinedev/core";

export const ListProducts = () => {
const {
tableQuery: { data, isLoading },
current,
setCurrent,
pageCount,
sorters,
setSorters,
} = useTable({
resource: "products",
pagination: { current: 1, pageSize: 10 },
sorters: { initial: [{ field: "id", order: "asc" }] },
});

/* ... */
};

Updating the ShowProduct Component

Let's update our <ShowProduct /> component and omit the resource and id parameters. Remember that previously we've hard-coded the id parameter. Now we'll be letting Refine to infer the id parameter from the route definition and dynamically fetch the product.

We'll also start using useShow hook which is wrapper around useOne. Unlike the useOne hook, it offers inference capabilities, eliminating the need to explicitly pass resource and id parameters

Update your src/pages/products/show.tsx file by adding the following lines:

src/pages/products/show.tsx
import { useShow } from "@refinedev/core";

export const ShowProduct = () => {
const { data, isLoading } = useOne({ resource: "products", id: 123 });
const { query } = useShow();

/* ... */
};

Updating the EditProduct Component

Let's update our <EditProduct /> component and omit the resource, action and id parameters from the useForm hook. Just like the <ShowProduct /> component, we'll be letting Refine to infer the id parameter from the route definition. Since we've defined the edit action in our resource definition, Refine will also infer the action parameter as edit.

Update your src/pages/products/edit.tsx file by adding the following lines:

src/pages/products/edit.tsx
import { useForm, useSelect } from "@refinedev/core";

export const EditProduct = () => {
const { onFinish, mutation, query } = useForm({
action: "edit",
resource: "products",
id: "123",
});
const { onFinish, mutation, query } = useForm();

/* ... */
};

Updating the CreateProduct Component

Let's update our <CreateProduct /> component and omit the resource and action parameters from the useForm hook. Since we've defined the create action in our resource definition, Refine will also infer the action parameter as create.

Update your src/pages/products/create.tsx file by adding the following lines:

src/pages/products/create.tsx
import { useForm, useSelect } from "@refinedev/core";

export const CreateProduct = () => {
const { onFinish, mutation } = useForm({
action: "create",
resource: "products",
});
const { onFinish, mutation } = useForm();

/* ... */
};

Now you should be able to see that our components are working as expected. We've successfully updated our components to benefit from the parameter inference of Refine.

In the next step, we'll be learning about how to handle redirects in our app.

Was this helpful?
import { useTable, useMany, useNavigation } from "@refinedev/core";

import { Link } from "react-router-dom";

export const ListProducts = () => {
  const {
    tableQuery: { data, isLoading },
    current,
    setCurrent,
    pageCount,
    sorters,
    setSorters,
  } = useTable({
    resource: "protected-products",
    pagination: { current: 1, pageSize: 10 },
    sorters: { initial: [{ field: "id", order: "asc" }] },
  });

  // You can also use methods like show or list to trigger navigation.
  // We're using url methods to provide more semantically correct html.
  const { showUrl, editUrl } = useNavigation();

  const { data: categories } = useMany({
    resource: "categories",
    ids: data?.data?.map((product) => product.category?.id) ?? [],
  });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  const onPrevious = () => {
    if (current > 1) {
      setCurrent(current - 1);
    }
  };

  const onNext = () => {
    if (current < pageCount) {
      setCurrent(current + 1);
    }
  };

  const onPage = (page: number) => {
    setCurrent(page);
  };

  const getSorter = (field: string) => {
    const sorter = sorters?.find((sorter) => sorter.field === field);

    if (sorter) {
      return sorter.order;
    }
  };

  const onSort = (field: string) => {
    const sorter = getSorter(field);
    setSorters(
      sorter === "desc"
        ? []
        : [
            {
              field,
              order: sorter === "asc" ? "desc" : "asc",
            },
          ],
    );
  };

  const indicator = { asc: "⬆️", desc: "⬇️" };

  return (
    <div>
      <h1>Products</h1>
      <table>
        <thead>
          <tr>
            <th onClick={() => onSort("id")}>
              ID {indicator[getSorter("id")]}
            </th>
            <th onClick={() => onSort("name")}>
              Name {indicator[getSorter("name")]}
            </th>
            <th>Category</th>
            <th onClick={() => onSort("material")}>
              Material {indicator[getSorter("material")]}
            </th>
            <th onClick={() => onSort("price")}>
              Price {indicator[getSorter("price")]}
            </th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
          {data?.data?.map((product) => (
            <tr key={product.id}>
              <td>{product.id}</td>
              <td>{product.name}</td>
              <td>
                {
                  categories?.data?.find(
                    (category) => category.id == product.category?.id,
                  )?.title
                }
              </td>
              <td>{product.material}</td>
              <td>{product.price}</td>
              <td>
                <Link to={showUrl("protected-products", product.id)}>Show</Link>
                <Link to={editUrl("protected-products", product.id)}>Edit</Link>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <div className="pagination">
        <button type="button" onClick={onPrevious}>
          {"<"}
        </button>
        <div>
          {current - 1 > 0 && (
            <span onClick={() => onPage(current - 1)}>{current - 1}</span>
          )}
          <span className="current">{current}</span>
          {current + 1 < pageCount && (
            <span onClick={() => onPage(current + 1)}>{current + 1}</span>
          )}
        </div>
        <button type="button" onClick={onNext}>
          {">"}
        </button>
      </div>
    </div>
  );
};
installing dependencies
installing dependencies