我有一个React前端和Laravel后端与MySql数据库的项目。我试图通过构建这个项目来学习React和Laravel。
如果用户还没有登录,我正在尝试将产品放入Redux。用户登录后,我试图将产品从Redux移动到数据库中的购物车表,包括user_id。如果用户在将产品添加到Redux之前登录,我会尝试将产品直接保存到数据库的购物车表中。有人能帮我写代码吗?
amazonSlice.js
import React, { useEffect, useState } from 'react'
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
const initialState = {
products: [],
userInfo:[],
status: 'idle'
};
export const updateCartOnSignIn = createAsyncThunk('amazon/updateCartOnSignIn', async (selectItems, { getState }) => {
const [apitoken, setapitoken] = useState('');
useEffect(() => {
const storedapitoken = localStorage.getItem('api_token');
if (storedapitoken) {
setapitoken(storedapitoken);
}
}, []);
const { userInfo } = getState().amazon;
try {
const response = await axios.post('http://127.0.0.1:8000/api/user/updatecart',{user_id: userInfo.id, selectItems}, {
headers: {
Authorization: `Bearer ${apitoken}`,
},
});
return response.data;
} catch (error) {
throw error;
}
}
);
export const amazonSlice = createSlice({
name: "amazon",
initialState,
reducers: {
// Actions
addToCart: (state, action) => {
const item = state.products.find((item) => item.id === action.payload.id)
if(item) {
item.quantity += action.payload.quantity
} else {
state.products.push(action.payload)
}
},
removeFromCart: (state, action) => {
state.products = state.products.filter((item) => item.id !== action.payload)
},
clearCart: (state) => {
state.products = []
window.scrollTo({ top: 0 });
},
quantityIncrement: (state,action) => {
const item = state.products.find((item) => item.id === action.payload)
item.quantity++
},
quantityDecrement: (state, action) => {
const item = state.products.find((item) => item.id === action.payload)
if(item.quantity === 1) {
item.quantity = 1
} else {
item.quantity --
}
}
},
});
export const { addToCart, removeFromCart, clearCart, quantityIncrement, quantityDecrement } = amazonSlice.actions;
// Selectors - This is how we pull information from the Global store slice
export const selectItems = (state) => state.amazon.products;
export const selectTotal = (state) => state.amazon.products.reduce((total, item) => total + (item.price * item.quantity) , 0)
export default amazonSlice.reducer;
Product.js
import Image from 'next/legacy/image'
import React, { useEffect, useState } from 'react'
import { StarIcon } from '@heroicons/react/24/solid'
import Currency from 'react-currency-formatter';
import prime from '../../images/prime.png'
import axios from 'axios';
import { useDispatch, useSelector } from 'react-redux';
import { addToCart, updateCartOnSignIn, selectItems, clearCart } from '@/slices/amazonSlice';
const Product = ({ id, title, price, description, category, src }) => {
const dispatch = useDispatch()
const itemsInCart = useSelector(selectItems);
const [apitoken, setapitoken] = useState('');
const [userid, setuserid] = useState('');
useEffect(() => {
const storedUsername = localStorage.getItem('api_token');
const storedUserid = localStorage.getItem('userid');
if (storedUsername && storedUserid) {
setapitoken(storedUsername);
setuserid(storedUserid);
}
}, []);
async function clickAddToCart(e) {
const isAuthenticated = !!apitoken;
if(!isAuthenticated) {
dispatch(addToCart({
id,
title,
description,
price,
category,
src,
quantity: 1,
}))
}
else if(isAuthenticated && itemsInCart.length > 0 ) {
try {
dispatch(updateCartOnSignIn);
dispatch(clearCart());
} catch (error) {
alert(error);
}
}
else {
let response = await axios.post('http://127.0.0.1:8000/api/user/updatecart', {id, title, price, description, category, src, quantity:1}, {
headers: {
Authorization: `Bearer ${apitoken}`
}
})
if(response) {
console.log(response)
}
dispatch(addToCart({
id,
title,
description,
price,
category,
src,
quantity: 1,
}))
}
}
return (
<div className='relative flex flex-col m-5 bg-white z-30 p-10'>
<p className='absolute -top-2 right-2 text-xs italic text-gray-400 my-3'>{category}</p>
<img src={src} width={200} height={200} style={{ objectFit: 'contain', paddingBottom: '13px' }} alt="img" />
<h4>{title}</h4>
<p className='text-sm my-2 line-clamp-2'>{description}</p>
<div className='mb-5'>
{/* currency is USD by default */}
<Currency quantity={price} />
</div>
<button onClick={clickAddToCart} className='mt-auto button'>Add to Basket</button>
</div>
)
}
export default Product
api.php
Route::middleware('auth:sanctum')->post('/user/updatecart', [ProductController::class, 'updatecart']);
ProductController.php
public function updateCart(Request $request) {
if (Auth::check()) {
$user_id = Auth::id();
$existingCartItem = Cart::where('user_id', $user_id)
->where('product_id', $request->id)
->first();
if ($existingCartItem) {
$existingCartItem->quantity += $request->quantity;
$existingCartItem->save();
} else {
$cart = new Cart();
$cart->user_id = $user_id;
$cart->product_id = $request->id;
$cart->quantity = $request->quantity;
$cart->save();
}
return response()->json(['message' => 'Cart updated successfully']);
} else {
return response()->json(['message' => 'User not authenticated'], 401);
}
}
购物车迁移文件
public function up()
{
Schema::create('carts', function (Blueprint $table) {
$table->id();
$table->string('user_id');
$table->string('product_id');
$table->string('quantity');
$table->timestamps();
});
}
1条答案
按热度按时间qvk1mo1f1#
在您的
Product component
中,您正在正确地分派操作以在Redux中将项目添加到购物车。但是,当用户通过身份验证时,您可以分派updateCartOnSignIn
操作,但不向其传递任何数据。您应该将itemsInCart数组作为参数传递给此操作,以便将其发送到服务器。以下是如何在
Product component
中更新clickAddToCart函数: