Reputation: 444
I was trying to display an array of data fetched from my custom server with RTK Query using Next.js (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 Next.js always throws 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.
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;
Upvotes: 8
Views: 17925
Reputation: 44086
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>
);
};
Upvotes: 9