所以,我有一个简单的例子,当一个未登录的访问者将产品添加到购物车,然后结帐,他们将被重定向到登录/注册页面,这种情况下,它的工作正常.但当一个登录的用户将产品添加到购物车,然后结帐,它仍然重定向到localhost:3000/login/shipping,当它应该是localhost:3000/shipping.
这是CartScreen.js
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
import Message from "../components/Message";
import {
Row,
Col,
ListGroup,
Image,
ListGroupItem,
Button,
FormControl,
Card,
} from "react-bootstrap";
import { addToCart, removeFromCart } from "../actions/cartActions";
export const CartScreen = () => {
const { id } = useParams();
const { search } = useLocation();
const history = useNavigate();
const productId = id;
const qty = search ? Number(search.split("=")[1]) : 1;
const dispatch = useDispatch();
const cart = useSelector((state) => state.cart);
const { cartItems } = cart;
console.log(cartItems);
useEffect(() => {
if (productId) {
dispatch(addToCart(productId, qty));
}
}, [dispatch, productId, qty]);
const removeFromCartHandler = (id) => {
dispatch(removeFromCart(id));
};
const checkoutHandler = () => {
history("/login?redirect=shipping");
};
return (
<Row>
<Col md={8}>
<h1>Shopping Cart</h1>
{cartItems.length === 0 ? (
<Message>
Your Cart is Empty <Link to="/">Go Back</Link>
</Message>
) : (
<ListGroup variant="flush">
{cartItems.map((item) => (
<ListGroupItem key={item.product}>
<Row>
<Col md={2}>
<Image src={item.image} alt={item.name} fluid rounded />
</Col>
<Col md={3}>
<Link to={`/product/${item.product}`}>{item.name}</Link>
</Col>
<Col md={2}>${item.price}</Col>
<Col md={2}>
<FormControl
as="select"
value={item.qty}
onChange={(e) =>
dispatch(
addToCart(item.product, Number(e.target.value))
)
}
>
{[...Array(item.countInStock).keys()].map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))}
</FormControl>
</Col>
<Col md={2}>
<Button
type="button"
variant="light"
onClick={(e) => removeFromCartHandler(item.product)}
>
<i className="fas fa-trash"></i>
</Button>
</Col>
</Row>
</ListGroupItem>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
<Card>
<ListGroup variant="flush">
<ListGroupItem>
<h2>
SubTotal ({cartItems.reduce((acc, item) => acc + item.qty, 0)})
items
</h2>
$
{cartItems
.reduce((acc, item) => acc + item.qty * item.price, 0)
.toFixed(2)}
</ListGroupItem>
<ListGroupItem>
<Button
type="button"
className="btn-block"
disabled={cartItems.length === 0}
onClick={checkoutHandler}
>
Proceed to Checkout
</Button>
</ListGroupItem>
</ListGroup>
</Card>
</Col>
</Row>
);
};
export default CartScreen;
这里有一个checkoutHandler函数的onClick操作的 checkout 按钮
const checkoutHandler = () => {
history("/login?redirect=shipping");
}
如果是后端问题或者是简单的重定向问题,那么这些是负责处理注册和登录的后端文件。
userController.js
import asyncHandler from "express-async-handler";
import User from "../models/userModel.js";
import mongoose from "mongoose";
import generateToken from "../utils/generateToken.js";
// @desc Auth user & get token
// @route POST /api/users/login
// @access Public
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id),
});
} else {
res.status(401);
throw new Error("Invalid email or password");
}
});
// @desc Register new user
// @route POST /api/users
// @access Public
const registerUser = asyncHandler(async (req, res) => {
const { name, email, password } = req.body;
const userExists = await User.findOne({ email });
if (userExists) {
res.status(400);
throw new Error("user already exists");
}
const user = await User.create({
name,
email,
password,
});
if (user) {
res.status(201).json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id),
});
} else {
res.status(400);
throw new Error("invalid user data");
}
});
// @desc Get user profile
// @route GET /api/users/profile
// @access Private
const getUserProfile = asyncHandler(async (req, res) => {
const user = await User.findById(req.user._id);
if (user) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
});
} else {
res.status(401);
throw new Error("No user found");
}
});
// @desc Update user profile
// @route PUT /api/users/profile
// @access Private
const updateUserProfile = asyncHandler(async (req, res) => {
const user = await User.findById(req.user._id);
if (user) {
user.name = req.body.name || user.name;
user.email = req.body.email || user.email;
if (req.body.password) {
user.password = req.body.password;
}
const updatedUser = await user.save();
res.json({
_id: updatedUser._id,
name: updatedUser.name,
email: updatedUser.email,
isAdmin: updatedUser.isAdmin,
token: generateToken(updatedUser._id),
});
} else {
res.status(401);
throw new Error("No user found");
}
});
export { authUser, getUserProfile, registerUser, updateUserProfile };
userRoutes.js
import express from "express";
import {
authUser,
getUserProfile,
registerUser,
updateUserProfile,
} from "../controllers/userController.js";
import { protect } from "../middleware/authMiddleware.js";
const router = express.Router();
router.post("/login", authUser);
router.route("/").post(registerUser);
router
.route("/profile")
.get(protect, getUserProfile)
.put(protect, updateUserProfile);
export default router;
authMiddleware.js
import jwt from 'jsonwebtoken'
import asyncHandler from 'express-async-handler'
import User from '../models/userModel.js'
const protect = asyncHandler(async(req, res, next) => {
let token
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer')){
try {
token = req.headers.authorization.split(' ')[1]
const decoded = jwt.verify(token, process.env.JWT_SECRET)
//console.log(decoded)
req.user = await User.findById(decoded.id).select('-password')
//next()
} catch (error) {
console.error(error)
res.status(401)
throw new Error ('Not authorization, token failed')
}
}
if(!token){
res.status(401)
throw new Error("Not authorized, no token")
}
next()
})
export {protect}
这些是负责注册和登录的redux文件。
userActions.js
import {
USER_DETAILS_FAIL,
USER_DETAILS_REQUEST,
USER_DETAILS_SUCCESS,
USER_LOGIN_FAIL,
USER_LOGIN_REQUEST,
USER_LOGIN_SUCCESS,
USER_LOGOUT,
USER_REGISTER_FAIL,
USER_REGISTER_REQUEST,
USER_REGISTER_SUCCESS,
USER_UPDATE_PROFILE_FAIL,
USER_UPDATE_PROFILE_REQUEST,
USER_UPDATE_PROFILE_SUCCESS,
} from "../constants/userConstants";
import axios from "axios";
export const login = (email, password) => async (dispatch) => {
try {
dispatch({
type: USER_LOGIN_REQUEST,
});
const config = {
headers: {
"content-type": "application/json",
},
};
const { data } = await axios.post(
"/api/users/login",
{ email, password },
config
);
dispatch({
type: USER_LOGIN_SUCCESS,
payload: data,
});
localStorage.setItem("userInfo", JSON.stringify(data));
} catch (error) {
dispatch({
type: USER_LOGIN_FAIL,
payload:
error.message && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
export const logout = () => (dispatch) => {
localStorage.removeItem("userInfo");
dispatch({ type: USER_LOGOUT });
};
export const register = (name, email, password) => async (dispatch) => {
try {
dispatch({
type: USER_REGISTER_REQUEST,
});
const config = {
headers: {
"content-type": "application/json",
},
};
const { data } = await axios.post(
"/api/users",
{ name, email, password },
config
);
dispatch({
type: USER_REGISTER_SUCCESS,
payload: data,
});
dispatch({
type: USER_LOGIN_SUCCESS,
payload: data,
});
localStorage.setItem("userInfo", JSON.stringify(data));
} catch (error) {
dispatch({
type: USER_REGISTER_FAIL,
payload:
error.message && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
export const getUserDetails = (id) => async (dispatch, getState) => {
try {
dispatch({
type: USER_DETAILS_REQUEST,
});
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
"content-type": "application/json",
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.get(`/api/users/${id}`, config);
dispatch({
type: USER_DETAILS_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: USER_DETAILS_FAIL,
payload:
error.message && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
export const updateUserProfile = (user) => async (dispatch, getState) => {
try {
dispatch({
type: USER_UPDATE_PROFILE_REQUEST,
});
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
"content-type": "application/json",
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.put(`/api/users/profile`, user, config);
dispatch({
type: USER_UPDATE_PROFILE_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: USER_UPDATE_PROFILE_FAIL,
payload:
error.message && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
userReducers.js
import {
USER_DETAILS_FAIL,
USER_DETAILS_REQUEST,
USER_DETAILS_SUCCESS,
USER_LOGIN_FAIL,
USER_LOGIN_REQUEST,
USER_LOGIN_SUCCESS,
USER_LOGOUT,
USER_REGISTER_FAIL,
USER_REGISTER_REQUEST,
USER_REGISTER_SUCCESS,
USER_UPDATE_PROFILE_FAIL,
USER_UPDATE_PROFILE_REQUEST,
USER_UPDATE_PROFILE_SUCCESS,
} from "../constants/userConstants";
export const userLoginReducer = (state = {}, action) => {
switch (action.type) {
case USER_LOGIN_REQUEST:
return { loading: true };
case USER_LOGIN_SUCCESS:
return { loading: false, userInfo: action.payload };
case USER_LOGIN_FAIL:
return { loading: false, error: action.payload };
case USER_LOGOUT:
return {};
default:
return state;
}
};
export const userRegisterReducer = (state = {}, action) => {
switch (action.type) {
case USER_REGISTER_REQUEST:
return { loading: true };
case USER_REGISTER_SUCCESS:
return { loading: false, userInfo: action.payload };
case USER_REGISTER_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
export const userDetailsReducer = (state = { user: {} }, action) => {
switch (action.type) {
case USER_DETAILS_REQUEST:
return { ...state, loading: true };
case USER_DETAILS_SUCCESS:
return { loading: false, user: action.payload };
case USER_DETAILS_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
export const userUpdateProfileReducer = (state = {}, action) => {
switch (action.type) {
case USER_UPDATE_PROFILE_REQUEST:
return { ...state, loading: true };
case USER_UPDATE_PROFILE_SUCCESS:
return { loading: false, success: true, userInfo: action.payload };
case USER_UPDATE_PROFILE_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
1条答案
按热度按时间h6my8fg21#
我有同样的问题很难,我解决了它与改变LoginScreen文件,在第一次我是从window.location获得位置值,这就是为什么它不为我工作的原因,在改变LoginScreen文件中的代码后:
至: