I am new to react and react-router-dom. I need your help to learn to how to get the parameter from the react-router. So I thank you in advance for taking your time on my problem. I am trying to recreate a SPA shop using react. You can find my code at this GitHub link.
These are the dependencies that i am using:
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"axios": "^0.26.1",
"react": "^18.0.0",
"react-bootstrap": "^2.2.3",
"react-dom": "^18.0.0",
"react-redux": "^7.2.8",
"react-router-bootstrap": "^0.26.1",
"react-router-dom": "^6.3.0",
"react-scripts": "^2.1.3",
"redux": "^4.1.2",
"redux-devtools-extension": "^2.13.9",
"redux-thunk": "^2.4.1",
"web-vitals": "^2.1.4"
}
what I want is to create a shopping cart by adding the object in quantity. By using redux I am trying to redirect my user to the shopping cart. at first, I wanted to use "history" and the optional parameter "?", however, I found that they are not supported in react v6 so I used another hook called "useNavigate". the code in my productScreen.js is as follows:
import React, { useState, useEffect } from "react";
import { Link, useParams, useNavigate } from "react-router-dom";
import {
Row,
Col,
Image,
ListGroup,
Card,
Button,
Form,
} from "react-bootstrap";
import Rating from "../components/Rating";
import { useDispatch, useSelector } from "react-redux";
import { listProductDetails } from "../actions/productActions";
import Loader from "../components/Loader";
import Message from "../components/Message";
const ProductScreen = () => {
const [qty, setQty] = useState(1);
const { id } = useParams();
const dispatch = useDispatch();
const productDetails = useSelector((state) => state.productDetails);
const { loading, error, product } = productDetails;
useEffect(() => {
dispatch(listProductDetails(id));
}, [dispatch, id]);
const navigate = useNavigate();
const addToCartHandler = () => {
navigate(`/cart/${id}?qty=${qty}`);
};
return (
<>
<Link className="btn btn-dark my-3" to="/">
Go Back
</Link>
{loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<Row>
<Col ms={6}>
<Image src={product.image} alt={product.name} fluid />
</Col>
<Col md={3}>
<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.Item>
<Row>
<Col>Status</Col>
<Col>
{product.countInStock > 0 ? "InStock" : "Out of Stock"}
</Col>
</Row>
</ListGroup.Item>
{product.countInStock > 0 && (
<ListGroup.Item>
<Row>
<Col>Qty</Col>
<Col>
<Form.Control
as="select"
value={qty}
onChange={(e) => setQty(e.target.value)}
>
{[...Array(product.countInStock).keys()].map((x) => (
<option key={x 1} value={x 1}>
{x 1}
</option>
))}
</Form.Control>
</Col>
</Row>
</ListGroup.Item>
)}
<ListGroup.Item>
<Button
className="btn-block"
type="button"
disabled={product.countInStock === 0}
onClick={addToCartHandler}
>
Add To Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
)}
</>
);
};
export default ProductScreen;
I am using navigate to redirect users to my cart and also bypassing the id parameter and qty as a query string to connect to local storage and the database.
Since optional parameter is not supported in react router v6, I deigned my routers as follow:
<Routes>
<Route path="/" element={<HomeScreen />} />
<Route path="/product/:id" element={<ProductScreen />} />
<Route path="/cart" element={<CartScreen />} />
<Route path="/cart/:id" element={<CartScreen />} />
</Routes>
In my cartScreen.js file, I can get the query using a hook called "research".On the other hand, when I try to get the id parameter, the "useParam" hook returns undefined.
import React, { useEffect } from "react";
import {
Link,
useSearchParams,
useNavigate,
useParams,
} from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import Message from "../components/Message";
import {
Row,
Col,
ListGroup,
Image,
Form,
Button,
Card,
} from "react-bootstrap";
import { addToCart } from "../actions/cartActions";
import { disable } from "colors";
const CartScreen = () => {
const { productID } = useParams();
console.log(productID);
const [qtyString] = useSearchParams();
const qty = Number(qtyString.toString().split("=")[1]);
console.log(qty)
const dispatch = useDispatch();
useEffect(() => {
if (productID) {
dispatch(addToCart(productID, qty));
}
}, [dispatch, productID, qty]);
return <div>CartScreen</div>;
};
export default CartScreen;
Would you mind teaching me how can I get the parameter ("id") from the router? any help would be appreciated. Thank you,
CodePudding user response:
So your issue is on this line
const { productID } = useParams(); <=========
here you have to put the same name you have defined in the Routes which in your case is :id
see below
<Route path="/product/:id" element={<ProductScreen />} />
So what you need to do is follows:
const { id } = useParams();
CodePudding user response:
The param here is called id
: <Route path="/cart/:id" element={<CartScreen />} />
You got it right for products: const { id } = useParams();
But in cart you've called it productID
:
const { productID } = useParams();
console.log(productID);
Change it to:
const { id } = useParams();
console.log(id);