为什么 "useParams()" return "undefined"?需要反应路由器/可选参数/useParams 的帮助

Why does "useParams()" return "undefined"? Need help for react router/ optional parameter/ useParams

我是 react 和 react-router-dom 的新手。我需要你的帮助来学习如何从 react-router 获取参数。因此,我提前感谢您花时间解决我的问题。 我正在尝试使用 React 重新创建一个 SPA 店。您可以在 GitHub link.

找到我的代码

这些是我正在使用的依赖项:

"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"
}

我想要的是通过添加对象的数量来创建一个购物车。通过使用 redux,我试图将我的用户重定向到购物车。起初,我想使用“history”和可选参数“?”,但是,我发现它们在 react v6 中不受支持,所以我使用了另一个名为“useNavigate”的钩子。我的productScreen.js中的代码如下:

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;

我正在使用 navigate 将用户重定向到我的购物车,并绕过 id 参数和 qty 作为查询字符串来连接到本地存储和数据库。

由于 react router v6 不支持可选参数,我将我的路由器设计如下:

<Routes>
  <Route path="/" element={<HomeScreen />} />
  <Route path="/product/:id" element={<ProductScreen />} />
  <Route path="/cart" element={<CartScreen />} />
  <Route path="/cart/:id" element={<CartScreen />} />
</Routes>

在我的 cartScreen.js 文件中,我可以使用名为“research”的钩子获取查询。另一方面,当我尝试获取 id 参数时,“useParam”钩子 returns 未定义。

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;

你介意教我如何从路由器获取参数(“id”)吗?任何帮助,将不胜感激。 谢谢,

这里的参数叫做id:<Route path="/cart/:id" element={<CartScreen />} />

您做对了产品:const { id } = useParams();

但在购物车中您将其命名为 productID:

const { productID } = useParams();
console.log(productID);

改为:

const { id } = useParams();
console.log(id);

所以你的问题就在这条线上

const { productID } = useParams(); <=========

在这里你必须输入你在路由中定义的相同名称,在你的情况下是 :id 见下文

<Route path="/product/:id" element={<ProductScreen />} />

所以你需要做的是:

const { id } = useParams();