【问题标题】:Managing State - multiple React Router links (ecommerce shopping cart)管理状态 - 多个 React Router 链接(电子商务购物车)
【发布时间】:2021-01-25 04:30:49
【问题描述】:

我正在建立一个电子商务网站。现在,我正在从 API 中提取项目并显示它们(“Shop”组件)。我可以单击一个项目以转到一个项目页面(“项目”组件),其中包含有关单击项目的更多详细信息/信息。当我点击“添加到购物车”按钮(在“商品”组件中)时,点击的商品会显示在购物车屏幕(“购物车”组件)中。

为了将项目从一个页面移动到另一个页面,我正在使用 React Router(请参阅“App”组件),并使用 <Link /> 来显示特定参数。我使用参数来传递商品 ID(和数量),以便调用该特定商品的 API。

这适用于一件商品,但我如何调整我的代码以允许在购物车中显示多件商品?

非常感谢任何反馈。

应用组件:

import React, { useState } from 'react';
import './App.css';
import Nav from './Nav';
import Shop from './Components/Shop';
import Info from './Components/Info';
import Cart from './Components/Cart';
import Item from './Components/Item';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';

function App() {
    return (
      <Router>
        <div className="App">
          <Nav />

          <Route path="/" exact component={Shop} />
          <Route path="/Info" component={Info} />
          <Route path="/Cart/:id/:qty" component={Cart} />
          <Route path="/Item/:item" component={Item} />

        </div>
      </Router>
    )
}

export default App;

商店组件:

import React, { useState, useEffect } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
import {Link} from 'react-router-dom';

function Shop() {

const [products, setProducts] = useState([]);
const [filterProducts, setFilteredProducts] = useState([]);
const [item, setItem] = useState('');
const [currentSort, setCurrentSort] = useState('');
const [loading, setLoading] = useState(false);

useEffect(async () => {
  fetchItems();
}, [])

const fetchItems = async () => {
  const data = await fetch('https://fakestoreapi.com/products');
  const items = await data.json();
  setProducts(items)
  setLoading(true)
}
function priceUSD(change){
  return change.toFixed(2)
}

useEffect(() => {
  const filteredItems = products.filter((a) => {
    if (item === '') {return a} else {return a.category === item}
  });
  setFilteredProducts(filteredItems);
}, [item, products])

 useEffect(() => {
  if (currentSort === '') {
    return
  }
  const sortedItems = filterProducts.sort((a, b) => {
    return currentSort === 'ASE' ? a.price - b.price : b.price - a.price
  });
  setFilteredProducts([...sortedItems]);
}, [currentSort])

    return (
        <div>
          <div className="itemSort">
            <p onClick={() => setItem("")}>All items</p>
            <p onClick={() => setItem("men clothing")}>Men clothing</p>
            <p onClick={() => setItem("women clothing")}>Women clothing</p>
            <p onClick={() => setItem("jewelery")}>Jewelery</p>
            <p onClick={() => setItem("electronics")}>Electronics</p>
          </div>

          <div className="itemSort">
            <p>Order by price</p>
            <p onClick={() => setCurrentSort('DESC')}>Highest</p>
            <p onClick={() => setCurrentSort('ASE')}>Lowest</p>
          </div>

            <div className="gridContainer">
              {loading ?
                          (filterProducts.map((a, index) => (
                            <Link to={`/Item/${a.id}`}>
                              <div key={index} className="productStyle">
                                <img src={a.image} className="productImage"></img>
                                <p>{a.title}</p>
                                <p>${priceUSD(a.price)}</p>
                              </div>
                            </Link>
                        )))  : (<ReactBootStrap.Spinner className="spinner" animation="border" />)
                        }
            </div>
        </div>
    )
}

export default Shop;

物品组件:

import React, { useState, useEffect } from 'react';
import {Link} from 'react-router-dom';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';

function Item(props) {
  const [product, setProduct] = useState([]);
  const [loading, setLoading] = useState(false);
  const [quantity, setQuantity] = useState(1);
  const [cost, setCost] = useState([]);

  useEffect(async () => {
    fetchItems();
  }, [])

  const itemId = props.match.params.item;
  const fetchItems = async () => {
    const data = await fetch('https://fakestoreapi.com/products/' + itemId);
    const items = await data.json();
    setProduct(items)
    setLoading(true)
    setCost(items.price)
  }

  function priceUSD(change){
    return change.toFixed(2)
  }

  useEffect(() => {
    const newCost = quantity * product.price;
    setCost(priceUSD(newCost))
  }, [quantity])

    return (
      <div className="App">
        <h2>Item</h2>
        <div className="gridContainer">
          {loading ?
                      (<div key={itemId} className="productStyle">
                            <img src={product.image} className="productImage"></img>
                            <p>{product.title}</p>
                            <p>{product.description}}</p>
                            <p>${priceUSD(product.price)}</p>

                            <div className="quantity">
                              <button className="btn minus-btn" type="button"
                                onClick={quantity > 1 ? () => setQuantity(quantity - 1) : null}>-</button>
                              <input type="text" id="quantity" placeholder={quantity}/>
                              <button className="btn plus-btn" type="button"
                                onClick={() => setQuantity(quantity + 1)}>+</button>
                            </div>

                            <Link to={`/Cart/${itemId}/${quantity}`}>
                              <button type="button">
                                Add to shopping cart ${cost}
                              </button>
                            </Link>

                          </div>
                      ): (<ReactBootStrap.Spinner className="spinner" animation="border" />)
                    }
        </div>
      </div>
    );
}

export default Item;

购物车组件:

import React, { useState, useEffect } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';

function Cart(props) {

    const [cart, setCart] = useState([]);
    const [quantity, setQuantity] = useState([]);
    const [loading, setLoading] = useState(false);

  useEffect(async () => {
  fetchItems();
}, [])

const itemId = props.match.params.id;
const itemQuantity = props.match.params.qty;
const fetchItems = async () => {
  const data = await fetch('https://fakestoreapi.com/products/' + itemId);
  const items = await data.json();
  setCart(items)
  setQuantity(itemQuantity)
  setLoading(true)
}

function price(qty){
  const newPrice = qty * cart.price;
  return newPrice
}

    return (
      <div>
        {loading ? (
          <div className="productStyle">
            <img src={cart.image} className="productImage"></img>
            <p>{cart.title}</p>

            <div className="quantity">
              <button className="btn minus-btn" type="button"
                onClick={quantity > 1 ? () => setQuantity(quantity - 1) : null}>-</button>
              <input type="text" id="quantity" placeholder={quantity}/>
              <button className="btn plus-btn" type="button"
                onClick={() => setQuantity(quantity + 1)}>+</button>
            </div>

            <p>${price(quantity)}</p>



          </div>
        ) : (<ReactBootStrap.Spinner className="spinner" animation="border" />)}
      </div>
    );
}

export default Cart;

【问题讨论】:

  • 您将购物车保存在哪里?就像客户刷新浏览器选项卡一样,您从哪里重新加载购物车?

标签: javascript reactjs


【解决方案1】:

如果您将购物车项目保存在localStorage 中会更好。

这样做,即使用户刷新选项卡,应用程序也可以从 localStorage 加载数据。

示例:-

  • 在浏览器中保存数据。
localStorage.setItem('my-app-cart-items', cartItems);
  • 从浏览器中检索数据。
const cartItems = localStorage.setItem('my-app-cart-items');
  • 从浏览器中删除数据
localStorage.removeItem('my-app-cart-items');

【讨论】:

  • 非常感谢,这是否也允许我将多个项目添加和存储到购物车,以便我可以在购物车中显示多个点击的项目?我可以从本地存储中删除项目吗?再次感谢您。
  • 是的,你可以。我已经更新了代码。还要在上述答案中检查localStorage 上的文档。
猜你喜欢
  • 1970-01-01
  • 2011-10-15
  • 1970-01-01
  • 2014-08-05
  • 2017-03-03
  • 2011-07-01
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
相关资源
最近更新 更多