I was trying to display an array of data fetched from my custom server with RTK Query using NextJS (React framework). And this is my first time using RTK Query. Whenever I console.log the data, it appears in the browser console. But whenever I try to map the data to render it in the browser, it keeps throwing an error saying "Cannot read properties of undefined (reading 'map')". I figured Nextjs always throw an error if an initial state is undefined or null even if the state change. This link talked about solving the problem using useMemo hook https://redux.js.org/tutorials/essentials/part-7-rtk-query-basics But I didn't understand it well. Please kindly help me out with displaying the data. Thanks so much in advance.
//Here is the BaseQuery function example I followed, it was derived from redux toolkit docmentation https://redux-toolkit.js.org/rtk-query/usage/customizing-queries#axios-basequery
import axios from "axios";
const axiosBaseQuery =
({ baseUrl } = { baseUrl: "" }) =>
async ({ url, method, data }) => {
try {
const result = await axios({ url: baseUrl url, method, data });
return { data: result.data };
} catch (axiosError) {
let err = axiosError;
return {
error: { status: err.response?.status, data: err.response?.data },
};
}
};
export default axiosBaseQuery;
//I make the GET request here
import { createApi } from "@reduxjs/toolkit/query/react";
import axiosBaseQuery from "./axiosBaseQuery";
export const getAllCarsApi = createApi({
reducerPath: "getAllCarsApi",
baseQuery: axiosBaseQuery({
baseUrl: "http://localhost:5000/",
}),
endpoints(build) {
return {
getAllCars: build.query({
query: () => ({ url: "all-cars", method: "get" }),
}),
};
},
});
export const { useGetAllCarsQuery } = getAllCarsApi;
//This is my redux store
import { configureStore } from "@reduxjs/toolkit";
import { getAllCarsApi } from "./getAllCarsApi";
import { setupListeners } from "@reduxjs/toolkit/dist/query";
const store = configureStore({
reducer: { [getAllCarsApi.reducerPath]: getAllCarsApi.reducer },
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(getAllCarsApi.middleware),
});
setupListeners(store.dispatch);
export default store;
//I provide the store to the _app.js file.
import "../styles/globals.css";
import axios from "axios";
import { MyContextProvider } from "@/store/MyContext";
import { Provider } from "react-redux";
import store from "@/store/ReduxStore/index";
axios.defaults.withCredentials = true;
function MyApp({ Component, pageProps }) {
return (
<MyContextProvider>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</MyContextProvider>
);
}
export default MyApp;
//I get the data here in my frontend.
import { useGetAllCarsQuery } from "@/store/ReduxStore/getAllCarsApi";
const theTest = () => {
const { data, isLoading, error } = useGetAllCarsQuery();
return (
<div>
{data.map((theData, i) => (
<h1 key={i}>{theData}</h1>
))}
<h1>Hello</h1>
</div>
);
};
export default theTest;
CodePudding user response:
This is a timing thing.
Your component will always render immediately and it will not defer rendering until data is there. That means it will also render before your data has been fetched. So while the data is still loading, data
is undefined
- and you try to map
over that.
You could do things like just checking if data is there to deal with that:
const theTest = () => {
const { data, isLoading, error } = useGetAllCarsQuery();
return (
<div>
{data && data.map((theData, i) => (
<h1 key={i}>{theData}</h1>
))}
<h1>Hello</h1>
</div>
);
};