React-Router-Dom v6多页面数据传递(首页→产品页→结算页)方案问询
React Router v6 页面间商品数据传递实现方案
需求说明
在React项目中,通过API在首页获取商品数据,需实现以下数据传递:
- 点击首页商品卡片的「Add to cart」按钮时,将当前商品的
image、name、price、description传递到Product页面 - 将该商品数据从Product页面传递到Checkout页面
实现步骤
1. 首页(Homepage.js):传递商品数据到Product页面
修改商品卡片的「Add to cart」按钮点击事件,利用navigate方法的第二个参数state携带目标商品数据:
// Homepage.js 中按钮部分修改 <button type="button" onClick={() => { navigate('/products', { state: { image: item.image, name: item.name, price: item.price, description: item.description } }) }} className="btn btn-warning" > Add to cart </button>
2. Product页面:接收数据并传递到Checkout页面
通过useLocation钩子接收首页传递的商品数据,同时修改页面内的「Add to cart」按钮,将数据继续传递到Checkout页面:
// Product.js 修改后的完整核心代码 import axios from 'axios' import { useEffect, useState } from "react"; import { useLocation, useNavigate } from 'react-router-dom' import img1 from '../images/beigehoodie.jpg' const Product = () => { const CONFIG_OBJ = { headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("token") } } const [allreview, setAllReview] = useState([]) const location = useLocation() const navigate = useNavigate() // 解构接收商品数据,添加默认值避免空数据报错 const { image, name, price, description } = location.state || {} const getReview = async () => { const response = await axios.get(`http://localhost:4000/getreview`, CONFIG_OBJ); if (response.status === 200) { setAllReview(response.data.review); } else { console.log("Error loading items") } } useEffect(() => { getReview() }, []); return ( <div className="container login-container"> <div className="row d-flex"> <div className="col-md-7 col-sm-12 "> {/* 使用传递的商品图片,默认值为本地图片 */} <img src={image || img1} className="instagram" width='400px' height='400px' /> </div> <div className="col-md-5 col-sm-12 "> <div className="card shadow"> <div className='col-md-12 text-center'> <div className="card"> <div className="card-header"> {/* 展示商品名称 */} <h5>{name || '商品名称'}</h5> </div> <ul className="list-group list-group-flush"> <li className="list-group-item">Rating</li> {/* 展示商品价格 */} <li className="list-group-item">{price || '0'}</li> {/* 展示商品描述 */} <li className="list-group-item">{description || '暂无描述'}</li> {/* 点击按钮传递数据到Checkout页面 */} <button onClick={() => { navigate('/checkout', { state: { image, name, price, description } }) }} className="btn btn-warning" > Add to cart </button> </ul> </div> </div> </div> </div> </div> {/* 以下为原有评论、评论表单部分,保持不变 */} <h2>Reviews</h2> <div> {allreview.map((review) => { return ( <div key={review._id}> <span className="border border-warning-subtle"> <table className="table"> <tbody> <tr> <th>Name</th> <td>{review.customer.fullName}</td> </tr> <tr> <th>Rating</th> <td>{review.star}</td> </tr> <tr> <th>Review</th> <td>{review.reviewText}</td> </tr> </tbody> </table> </span> </div> ) })} </div> <h2>Write a review</h2> <p>Ratings</p> <select className="form-select" aria-label="Default select example"> <option selected>Select</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> </select> <form> <div className="mb-3"> <label for="exampleInputEmail1" className="form-label">Write review</label> <input type="text" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"/> </div> </form> <button className="btn btn-warning">Submit</button> </div> ) } export default Product
3. Checkout页面:接收并使用商品数据
通过useLocation钩子接收Product页面传递的商品数据,用于订单摘要展示:
// Checkout.js 修改后的完整核心代码 import axios from 'axios' import { useEffect, useState } from "react"; import { useLocation } from 'react-router-dom' const Checkout = () => { const CONFIG_OBJ = { headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("token") } } const [alladdress, setAllAddress] = useState([]) const location = useLocation() // 解构接收商品数据 const { name, price } = location.state || {} const getAddress = async () => { const response = await axios.get(`http://localhost:4000/getaddress`, CONFIG_OBJ); if (response.status === 200) { setAllAddress(response.data.address); } else { console.log("Error loading items") } } useEffect(() => { getAddress() }, []); // 计算订单总价 const totalPrice = price ? parseInt(price) + 10 : 0 return ( <div className="container login-container"> <div className="row"> <div className="col-md-8 col-sm-12 justify-content-left" > {alladdress.map((add) => { return ( <div key={add._id}> <div className="card" > <div className="card-body justify-content-left"> <h5 className="card-title">Shipping</h5> <h6 className="card-subtitle mb-2 text-body-secondary">Name: {add.fullName}</h6> <p className="card-text">Address: {add.address},{add.city},{add.postalcode},{add.country}</p> <a href="#" className="card-link">Edit</a> </div> </div> </div> ) })} <div className="card" > <div className="card-body"> <h5 className="card-title">Payment</h5> <h6 className="card-subtitle mb-2 text-body-secondary">Card subtitle</h6> <p className="card-text">Method- Paypal</p> <a href="#" className="card-link">Edit</a> </div> </div> </div> <div className="col-md-4 col-sm-12 "> <div className="card shadow"> <div className='col-md-12 text-center'> <div className="card"> <div className="card-header"> <h2>Order Summary</h2> </div> <table className="table"> <tbody> <tr> <th>Item</th> <td>{name || '未选择商品'}</td> </tr> <tr> <th>Price</th> <td>{price || '0'}</td> </tr> <tr> <th>Shipping</th> <td>$0</td> </tr> <tr> <th>Tax</th> <td>$10</td> </tr> <tr> <th>Total</th> <td>{totalPrice}</td> </tr> </tbody> </table> <a href="#" className="btn btn-warning">Place order</a> </div> </div> </div> </div> </div> </div> ) } export default Checkout
关键说明
- React Router v6中,页面跳转传递数据的标准方式是使用
useNavigate的state参数,数据会被存储在浏览器的历史记录中 - 接收数据使用
useLocation钩子,从location.state中获取内容,需添加默认值避免页面刷新时state为空导致的报错 - 该方案无需依赖额外状态管理库,适合简单的页面间数据传递场景
内容的提问来源于stack exchange,提问作者Arpit Gupta
相关产品推荐
相关产品推荐

