I am not able to fetch the single product details through Redux-Toolkit (RTK) Query but get all products is working but not for single product.
constants.js:
export const BASE_URL='/';
export const PRODUCTS_URL='api/products/';
export const ORDERS_URL='api/orders';
export const USERS_URL='api/users';
export const PAYPAL_URL='api/config/paypal';
useGetProductsQuery
is fetching all the products from the api but the useGetProductDetailsQuery
is not fetching single product details
Store:
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { apiSlice } from './slices/apiSlice';
const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer
},
middleware:(getDefaultMiddleware) => getDefaultMiddleware().concat(apiSlice.middleware),
devTools: true
})
export default store;
apiSlice:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { BASE_URL, PRODUCTS_URL } from '../constants';
const baseQuery = fetchBaseQuery({ baseUrl: BASE_URL });
export const apiSlice = createApi({
baseQuery: baseQuery,
tagTypes: ["Product", "Order","User"],
endpoints: (builder) => ({
getProducts: builder.query({
query: () => ({
url: PRODUCTS_URL,
}),
keepUnusedDataFor: 5
}),
getProductDetails: builder.query({
query: (productId) => ({
url: `${PRODUCTS_URL}/${productId}`, // this url is not hitting the api and not fetching the data, but in postman its working fine
}),
keepUnusedDataFor: 5
}),
})
});
export const {
useGetProductDetailsQuery,
useGetProductsQuery
} = apiSlice;
Product Screen:
import { Link, useParams } from "react-router-dom";
import { Col, Row, Image, ListGroup, Card, Button } from "react-bootstrap";
import Rating from "../components/Rating";
import { useGetProductDetailsQuery } from "../slices/apiSlice";
const ProductScreen = () => {
const { id: productId } = useParams();
console.log(useGetProductDetailsQuery(productId))
const { data: product, isLoading, Error } = useGetProductDetailsQuery(productId);
return (
<>
<Link className="btn btn-light my-3" to="/">Go Back</Link>
<Row>
<Col md={5}>
<Image src={product.image} alt={product.name} fluid />
</Col>
<Col md={4}>
<ListGroup variant="flush">
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating value={product.rating} text={`${product.numReviews} reviews`} />
</ListGroup.Item>
<ListGroup.Item>
Price: ${product.price}
</ListGroup.Item>
<ListGroup.Item>
Description: {product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<Row>
<Col>Price:</Col>
<Col>
<strong>${product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
</ListGroup>
<ListGroup variant="flush">
<ListGroup.Item>
<Row>
<Col>Status:</Col>
<Col>
<strong>{product.countInStock>0?"In Stock":"Out of Stock"}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Button type="button" className="btn-block" disabled={product.countInStock===0}>
Add To Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</>
)
}
export default ProductScreen;
package.json:
{
"name": "frontend",
"version": "0.1.0",
"proxy": "http://localhost:5000",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.4.0",
"bootstrap": "^5.3.0",
"bootstrap-icons": "^1.10.5",
"react": "^18.2.0",
"react-bootstrap": "^2.8.0",
"react-dom": "^18.2.0",
"react-icons": "^4.10.1",
"react-redux": "^8.1.2",
"react-router-bootstrap": "^0.26.2",
"react-router-dom": "^6.14.2",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
I have also added the proxy. I don’t know why its not getting the product details.
2
Answers
The returned
data
property will be undefined until the query actually completes and has fetched data to provide. The UI code you have makes the assumption thatdata
is defined.See the query hook’s signature, specifically the properties dealing with data and query status:
You will want to at least check that
data
is defined prior to attempting to access into it for nested properties likedata.image
. TheisSuccess
is also a flag that indicates the query has data.Example:
@Drew Reese and @Basharat Khan, Please am still stucked here… Trying to understand what you guys meant about this " if (!product) {
return null; // or some fallback UI message about no data, etc
}"
please explain better for me