Search code examples
reactjstypescriptreact-router-domredux-toolkitrtk-query

How can i dispatch the redux/toolkit action in the react router dom action?


Here is my router

const router = createBrowserRouter([
  {
    path: "/",
    element: <MainLayout />,
    errorElement: <Error />,
    children: [
      {
        path: "/inventory",
        element: <Inventory />,
      },
      {
        path: "/inventory/:inventoryId",
        element: <InventoryItem />,
        action: inventoryAction
      },
    ],
  }
]);

Inside the inventoryItem. I got the inventoryAction exported. Since this action is not inside the component I can't call the useCreateNewItemMutation hook.

export const inventoryAction = async ({ request }: any) => {
  const data = await request.formData();
  let dataToSubmit = {
    unitName: data.get("unitName"),
    itemType: data.get("itemType"),
    price: data.get("price"),
    unitCount: data.get("unitCount"),
    inventoryId: data.get("inventoryId"),
  };
  // store.dispatch(useCreateNewItemMutation(dataToSubmit)) // HOW CAN I DISPATCH
  return null;
};

const InventoryItem = ({ params }: any) => {
  const { inventoryId } = useParams();

  const [addItemModalActive, setAddItemModalActive] = useState(false);
  
  return (
    <div>
      <Form
        method="post"
        action={`/inventory/${inventoryId}`}
        className="flex flex-col w-1/2"
      >
        <label className="text-sm text-gray-500 mb-2" htmlFor="item name">
          Item name
        </label>
        <input
          placeholder="Enter Item Name"
          id="item name"
          name="unitName"
          className="border rounded w-full mb-4 p-2 text-sm"
        ></input>

        <label className="text-sm text-gray-500 mb-2" htmlFor="item type">
          Item type
        </label>
        <input
          placeholder="Eg food,drink..."
          id="item type"
          name="itemType"
          className="border rounded w-full mb-4 p-2 text-sm"
        ></input>
      </Form>
    </div>
  );
};

As you can see in the inventoryAction function I want to call useCreateNewItemMutation hook.

How can I accomplish this?

store.ts

const store = configureStore({
  reducer: {
    [apiSlice.reducerPath]: apiSlice.reducer,
    auth: authSliceReducer,
    organization: organizationSliceReducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(apiSlice.middleware),
  devTools: true,
});

export const apiSlice = createApi({
  baseQuery,
  tagTypes: ["User", "Inventory", "Item"],
  endpoints: (builder) => ({}),
});

Here is the file which exporting the mutation function

export const itemApiSlice = apiSlice.injectEndpoints({
  endpoints: (builder) => ({
    createNewItem: builder.mutation({
      query: (data) => ({
        url: `http://localhost:3000/item`,
        method: "POST",
        body: data,
      }),
      
    }),
  }),
});

export const { useCreateNewItemMutation } = itemApiSlice;

Solution

  • You can't call React hooks outside React components and custom React hooks. In the loader you can manually dispatch actions directly to the store. The key here is that you can't use the generated React hooks from your endpoints, but you can manually initiate one.

    Example:

    import { store } from '../path/to/store';
    import { itemApiSlice } from '../path/to/itemApiSlice';
    
    export const inventoryAction = async ({ request }: any) => {
      const data = await request.formData();
    
      const dataToSubmit = {
        unitName: data.get("unitName"),
        itemType: data.get("itemType"),
        price: data.get("price"),
        unitCount: data.get("unitCount"),
        inventoryId: data.get("inventoryId"),
      };
    
      store.dispatch(
        itemApiSlice.endpoints.createNewItem.initiate(dataToSubmit)
      );
    
      return null;
    };