I'm having an issue with calling an auto created hook by Redux-Toolkit (RTK) Query (RTKQ). The issue I get is the following: "fetchInvoicesByOffice is not a function"
Store
import { configureStore } from "@reduxjs/toolkit";
import { InvoiceSlice } from "./Invoices/InvoiceSlice";
export const store = configureStore({
reducer: {
[InvoiceSlice.reducerPath]: InvoiceSlice.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(InvoiceSlice.middleware),
}
);
Slice
import { createApi, fetchBaseQuery } from
"@reduxjs/toolkit/query/react";
export const InvoiceSlice = createApi({
reducerPath: "InvoiceSlice",
baseQuery: fetchBaseQuery({
baseUrl: "http://INVOICES_API:8081/api/",
}),
tagTypes: ["Invoices"],
endpoints: (builder) => ({
fetchInvoices: builder.query({
query: () => "GetAllInvoices",
providesTags: ["Invoices"],
}),
fetchInvoice: builder.query({
query: (id) => `GetInvoice/${id}`,
providesTags: ["Invoices"],
}),
fetchInvoicesByOffice: builder.query({
query: (id) => `GetAllInvoices_ByOffice/${id}`,
providesTags: ["Invoices"],
}),
addInvoiceComment: builder.mutation({
query: (data) => ({
url: "addComment",
method: "POST",
body: data,
}),
invalidatesTags: ["Invoices"],
}),
updateInvoicesStatus: builder.mutation({
query: (data) => ({
url: "values",
method: "PUT",
body: data,
}),
invalidatesTags: ["Invoices"],
}),
AddMatter: builder.mutation({
query: (data) => ({
url: "UpdateMatter",
method: "PUT",
body: data,
}),
invalidatesTags: ["Invoices"],
}),
fetchInvoice: builder.query({
query: (id) => `GetComment/${id}`,
providesTags: ["Invoices"],
}),
}),
});
export const {
useFetchInvoicesQuery,
useFetchInvoiceQuery,
useFetchInvoicesByOfficeQuery,
useAddInvoiceCommentMutation,
useUpdateInvoicesStatusMutation,
} = InvoiceSlice;
Component
import React, { useState, useEffect } from "react";
import "./InvoiceList";
import "./InvoiceList.css";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { css } from "glamor";
import {
useFetchInvoicesQuery,
useLazyFetchInvoicesByOfficeQuery,
} from "../../features/Invoices/InvoiceSlice";
const InvoiceList = () => {
const { data, refetch } = useFetchInvoicesQuery();
const [fetchInvoicesByOffice, { currentData }] =
useLazyFetchInvoicesByOfficeQuery();
const [checked, setChecked] = useState(false);
const [rowClicked, setRowClicked] = useState(0);
const [office, setOffice] = useState("ALL");
const [selection, setSelection] = useState("ALL");
const [invoiceStatus, setInvoiceStatus] = useState();
const [matter, setMatter] = useState("");
const loggedUser = JSON.parse(localStorage.getItem("user"));
const [invoicesState, setInvoicesState] = useState([]);
const [term, setTerm] = useState("");
const [userid, setUserId] = useState("");
useEffect(() => {
setUserId(loggedUser);
setInvoicesState(data);
}, [data]);
let toastId = null;
const displayToast = (message) => {
if (!toast.isActive(toastId)) {
toastId = toast(`${message} !!! 🚀`, {
className: css({
background: "#9e007e !important",
color: "white !important",
fontWeight: "bold",
}),
autoClose: 1000,
closeOnClick: true,
toastId: "my_toast",
autoClose: true,
closeButton: false,
position: toast.POSITION.BOTTOM_CENTER,
});
}
};
const onSearchSubmit = (term) => {
setTerm(term);
};
const handleOfficeClick = async (offc) => {
setOffice(offc);
if (office === "ALL") {
refetch();
setInvoicesState(data);
} else {
setOffice((prevState) => {
fetchInvoicesByOffice(prevState);
setInvoicesState(currentData);
return !prevState;
});
// await fetchInvoicesByOffice(offc);
// await setInvoicesState(currentData);
}
};
useEffect(() => {
if (office === "ALL") {
setOffice(office);
fetchInvoicesByOffice("ALL");
} else {
setOffice(office);
fetchInvoicesByOffice(office);
}
}, [office]);
I want to be able to use the hook in either the useEffect
hook callback or the handleOfficeClick
handler...........................................................
The RTKQ query hook itself is what calls the endpoint and its return value is the fetched data and associated metadata.
See useQuery for more details. Here's a query hook's function signature.
type UseQuery = ( arg: any | SkipToken, options?: UseQueryOptions ) => UseQueryResult type UseQueryOptions = { pollingInterval?: number refetchOnReconnect?: boolean refetchOnFocus?: boolean skip?: boolean refetchOnMountOrArgChange?: boolean | number selectFromResult?: (result: UseQueryStateDefaultResult) => any } type UseQueryResult<T> = { // Base query state originalArgs?: unknown // Arguments passed to the query data?: T // The latest returned result regardless of hook arg, if present currentData?: T // The latest returned result for the current hook arg, if present error?: unknown // Error result if present requestId?: string // A string generated by RTK Query endpointName?: string // The name of the given endpoint for the query startedTimeStamp?: number // Timestamp for when the query was initiated fulfilledTimeStamp?: number // Timestamp for when the query was completed // Derived request status booleans isUninitialized: boolean // Query has not started yet. isLoading: boolean // Query is currently loading for the first time. No data yet. isFetching: boolean // Query is currently fetching, but might have data from an earlier request. isSuccess: boolean // Query has data from a successful load. isError: boolean // Query is currently in an "error" state. refetch: () => void // A function to force refetch the query }
If you want wanting to intentionally trigger a query/fetch in a callback then you are looking for the lazy queries. These return an array that includes a "trigger function".
const [trigger, result, lastPromiseInfo] = api.endpoints.getPosts.useLazyQuery(options);
From your API slice export the generated
export const {
useFetchInvoicesQuery,
useFetchInvoiceQuery,
useFetchInvoicesByOfficeQuery,
useLazyFetchInvoicesByOfficeQuery, // <-- lazy query
useAddInvoiceCommentMutation,
useUpdateInvoicesStatusMutation,
} = InvoiceSlice;
Import the lazy query hook in the UI and use the returned trigger function.
...
import {
...,
useLazyFetchInvoicesByOfficeQuery,
} from "../../features/Invoices/InvoiceSlice";
const InvoiceList = () => {
const { data, refetch } = useFetchInvoicesQuery();
const [fetchInvoicesByOffice] = useLazyFetchInvoicesByOfficeQuery();
const handleOfficeClick = async (offc) => {
await setChecked((old) => !old);
await setOffice(offc);
await fetchInvoicesByOffice(office);
};
useEffect(() => {
fetchInvoicesByOffice(office);
if (office === "ALL") refetch();
}, [office]);
...