javascript - 如何增加/减少购物车中产品的数量?
问题描述
我在实现从购物车中添加或删除产品的逻辑时遇到了一些困难。
首先在我的数据库级别:
- 每个购物篮包括:购物篮 ID、产品 ID、客户 ID 和数量。
这意味着用户实际上有“几个篮子”(一个产品=一个篮子)
后端
以下是我如何使用 sequelize 创建模型/关系:
// Inside db.config.js
db.paniers = sequelize.define('panier', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
field: 'PAN_ID'
},
userId: {
type: Sequelize.INTEGER,
references: {
model: db.users,
key: 'USE_ID'
},
primaryKey: true,
allowNull: false,
field: 'USE_ID'
},
produitId : {
type: Sequelize.INTEGER,
references: {
model: db.produits,
key: 'PRO_ID'
},
primaryKey: true,
allowNull: false,
field: 'PRO_ID'
},
quantite: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'PAN_QUANTITE'
}
}, {
tableName: 'PANIER'
});
然后对于查询,进行两个查询:
一个显示有关购物车的信息(购物车 ID、产品 ID、产品名称、产品价格、产品图片、购物车数量)
另一个更新数量。
这是我在 POSTMAN 下进行 axios 查询和结果的方式
const APIURL = 'http://localhost:8090/api';
// Get the details of the cart
export const getDetails = (userId) => axios.get(`${APIURL}/panier/details/${userId}`,
{
userId: userId,
});
// Update the quantity of the cart
export const updateQuantite = (produitId) => axios.put(`${APIURL}/panier/${produitId}`,
{
produitId: produitId,
});
// Result for the userId 1 (getDetails)
{
"PRO_ID": 1,
"PRO_NOM": "Un immeuble",
"PRO_PRIX": "1515",
"PRO_URL": "58afa4f2-41b1-42f7-a371-6d267784c44e.jpg",
"PAN_QUANTITE": 1,
"PAN_ID": 1
},
{
"PRO_ID": 2,
"PRO_NOM": "Model",
"PRO_PRIX": "102",
"PRO_URL": "a76fbe76-a183-49fa-84ee-40d5da08b91f.png",
"PAN_QUANTITE": 1,
"PAN_ID": 2
}
这是我的两个控制器管理他的路线:
// Display the informations of the basket
exports.getDetails = (req, res) => {
const queryResult = db.sequelize.query(
'SELECT P.PRO_ID, PRO_NOM, PRO_PRIX, PRO_URL, PA.PAN_QUANTITE, PA.PAN_ID\n' +
'FROM panier AS PA INNER JOIN produit AS P ON PA.PRO_ID = P.PRO_ID\n' +
'WHERE USE_ID = :id',
{
replacements: { id: req.params.userId },
type: QueryTypes.SELECT
}
).then(panier => {
res.json(panier);
}).catch(err => res.status(400).send(err));
}
// Modify the quantity of a basket
exports.update = (req, res) => {
Paniers.update({
quantite: req.body.quantite
}, {
where: {
produitId: req.params.produitId
}
}).then(panier => {
res.json(panier);
}).catch(err => res.status(400).send(err));
}
前端
这就是我的信息的显示方式(仍在开发中,这就是为什么它看起来不像任何东西^^')
这就是我迷路的地方......这是我的购物车 pagePage.js :
import React, { useState, useEffect } from 'react';
import { Card, CardHeader, CardMedia, Grid, ButtonGroup, Button} from '@material-ui/core';
import PayPal from '../services/PayPal/paypal'
import {getDetails, updateQuantite, getAllPanier, get} from '../services/API/panier'
export default function PanierPage() {
// Récupération des détails des paniers
const [paniers, setPaniers] = useState([])
const getPaniersDetails = () => [
getDetails(JSON.parse(localStorage.getItem('User')).id).then(response => {
setPaniers(response.data)
console.log(response)
}).catch(err => console.log(err))
]
const handleIncrement = (id) => {
updateQuantite(id).then(response => {
// ???
}).catch(err => console.log(err))
}
const handleDecrement = () => {
}
// Affichage des détails des paniers
const paniersAffichage = paniers.map((panier) => (
<Grid container>
<Card key={panier.PAN_ID}>
<CardHeader title={panier.PRO_NOM}/>
<CardMedia image={`http://localhost:8090/${panier.PRO_URL}`}/>
<Button onClick={() => handleIncrement(panier.PRO_ID)}> + </Button>
{panier.PAN_QUANTITE}
<Button onClick={handleDecrement}> - </Button>
</Card>
</Grid>
));
// Chargement des produits
useEffect(() => {
getPaniersDetails();
}, [])
return (
<>
<Grid>
{paniersAffichage}
</Grid>
<PayPal/>
</>
);
}
解释:
我在“getPaniersDetails”中获取我的购物篮信息,我在其中指出用户 ID,然后将其加载到我的 useEffect 中。
basketsDisplay 允许我显示相关用户的购物篮。
我在每张卡片中为映射提供购物车的 ID,然后显示信息……点击“+”时,我想增加我的数量,所以我给它提供了产品 ID。
因此,handleIncrement 将使用“updateQuantite”处理此操作。
这就是我阻止的地方,我觉得自己在不同的 ID 之间混在一起。特别是在表的购物车 ID 和我的查询(SELECT)的购物车 ID 之间
我敢肯定,设置起来非常简单,但在我看来,这对我来说似乎很复杂......
如果我错过了任何重要的点告诉我,我会尽力改变我的帖子
解决方案
您的对象模型没有多大意义。
我会改变它以使其更具活力。
如果您有用户,并且他们有一个购物篮属性,那么这种方法更有意义。
注意:下面的代码是一个粗略的大纲,但应该让您知道如何去做。
interface Database {
users: User[]; // Array of users.
}
interface User {
id: number;
username: string;
passwordHash: string;
baskets: Basket[];
}
interface Basket {
id: number;
items: Item[]; // array of items;
date: string;
}
interface Item {
id: number; // ID of the item.
name: string;
imgURL: string;
description: string[];
quantity: number;
}
现在,如果我们想要接收数据并将数据发送到数据库,我们会这样做。
interface Basket {
items: string[]; // list of item id's.
}
// You want to use a session token instead of the user id so noone but the user can access their basket.
// Normaly baskets will be local to the browser or app and not sored on a servers database.
// Only past orders should be stored. But in this example, we are storing the current basket too.
async function getBasket(sessionToken: string){
return await axios.get(`${api.host}/basket`, {
headers: {
Session-Token: sessionToken, // used to identify the user
Content-Type: "application/json",
}
}).data;
}
// we send the basket object, which is just a list of IDs, and the session token.
async function setBasket(basket: Basket, sessionToken: string){
return await axios.put(`${api.host}/basket`, {
headers: {
Session-Token: sessionToken, // used to identify the user
Content-Type: "application/json",
}
}).data;
}
现在在服务器端,我们可以使用 express 处理请求。
为了使用 express 实现会话,有一个 npm 模块express-session
,它是 express 的中间件。当用户登录时,他们将获得一个标头,他们将保存为 cookie 以用于他们未来的请求。当他们注销时,会话将从您的服务器中删除,并且 cookie 在客户端上被删除。
为了增加安全性,您可以设置会话的过期时间。用户将不得不重新登录并获得一个新会话。
// check the documentation to tune it to what you need.
app.use(session({
secret: 'mySuperSecret',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
app.get("/basket", async(req, res) => {
// here we first check if the session exists.
if(req.session.views){
// if it does, then we return the list of baskets.
const { baskets } = await getUser(req.session.userID);
res.sendStatus(200).send([success: true, data: baskets]);
}
// if not, then we will return a 403 error.
// we also send a response that matches the layout of the normal response.
res.sendStatus(403).send([success: false, data: []]);
})
app.put("/basket", (req, res) => {
// here we first check if the session exists.
if(req.session.views){
// if it does, then we add the basket to the user.
addBasket(req.session.userID, basket)
.then(res.sendStatus(204).send([success: true, data: []]))
}
// if not, then we will return a 403 error.
// we also send a response that matches the layout of the normal response.
res.sendStatus(403).send([success: false, data: []]);
})
如果您有任何问题,请在评论部分提出。我有空时会回复。
推荐阅读
- c# - 在 ASP.NET Core MVC App 中添加动态表单字段
- facebook - 使用 MoPub 接收非英语 Facebook 原生广告
- python - SyntaxError:python 中的语法无效但找不到原因
- c++ - 为什么我调整大小的 2D 矢量会重置我的数据
- c# - Telerik RadFileExplorer 修改 SaveAs 方法
- angular - RxJS:forkJoin 没有返回
- visual-studio-code - 在 VS Code 扩展中获取当前的 Highlight
- javascript - 清除所选选项并在提交表单后显示占位符
- ruby-on-rails - 引用 Rails 模型而不加载模型的单元测试代码
- android - 我需要从 Firebase DB 调用的唯一文件路径