问题描述
我为此花了 2 天时间,但不知道为什么。 我正在使用 React 构建一个电子商务网站,并且没有加载有效负载,只有“加载”状态被卡住为真,然后没有从后端获取任何数据。我已经尽我所能,发现只有“ProductInfo”页面试图从“localhost:3000/api/products”获取数据(后端端口是 5000,“Home”页面正确地从 5000 获取数据)
有人能找出哪里错了吗?
操作:
export const listProducts = () => async (dispatch) => {
dispatch({
type: ActionTypes.PRODUCTS_LIST_REQUEST
});
try {
const { data } = await Axios.get('/api/products');
dispatch({ type: ActionTypes.PRODUCTS_LIST_SUCCESS,payload: data });
} catch(error) {
dispatch({ type: ActionTypes.PRODUCTS_LIST_FAIL,payload: error.message});
}
};
export const detailsProduct = (productId) => async (dispatch) => {
dispatch({ type: ActionTypes.PRODUCT_DETAILS_REQUEST,payload: productId });
try {
const { data } = Axios.get(`/api/products/${productId}`);
await dispatch({ type: ActionTypes.PRODUCT_DETAILS_SUCCESS,payload: data });
} catch (error) {
dispatch({
type: ActionTypes.PRODUCT_DETAILS_FAIL,payload:
error.response && error.response.data.message
? error.response.data.message
: error.message
});
}
};
减速器:
export const productListReducer = (state={ loading: true,products: []},action) => {
switch(action.type) {
case PRODUCTS_LIST_REQUEST:
return { loading: true };
case PRODUCTS_LIST_SUCCESS:
return { loading: false,products: action.payload };
case PRODUCTS_LIST_FAIL:
return { loading: false,error: action.payload}
default:
return state;
}
};
export const productDetailsReducer = (state={ loading: true },action) => {
switch(action.type) {
case PRODUCT_DETAILS_REQUEST:
return { loading: true };
case PRODUCT_DETAILS_SUCCESS:
return { loading: false,product: action.payload};
case PRODUCT_DETAILS_FAIL:
return { loading: false,error: action.payload };
default:
return state;
}
};
App.js
function App() {
return (
<browserRouter>
<Header />
<Route path="/" component={Home} exact />
<Route path="/product/:id" component={ProductInfo} exact />
<Footer />
</browserRouter>
);
}
export default App;
import React,{ useState,useEffect } from 'react';
import { usedispatch,useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import ReactStars from 'react-rating-stars-component';
import Loading from '../LoadingComponent';
import MessageBox from '../MessageBoxComponent';
import { SELLERS } from '../../shared/sellers';
import './ProductInfo.css';
import { detailsProduct} from '../../redux/actionCreators';
function ProductInfo(props) {
const dispatch = usedispatch();
const productId = props.match.params.id;
const productDetails = useSelector((state) => state.productDetails);
const { loading,error,product } = productDetails;
console.log(productDetails);
useEffect((productId) => {
dispatch(detailsProduct(productId));
},[dispatch,productId]);
const seller = SELLERS.find((seller) => seller._id === product.sellerId);
const [ showImage,setShowImage ] = useState(product.imageUrl[0]);
const renderImages = product.imageUrl.map(image => (
<div className="info__smallImgBox" onClick={() => setShowImage(image)}>
<img
src={image}
className="info__smallImg"
alt={product.name+' image'}
/>
</div>
));
return (
<div className="info__container">
<Link to="/"><div className="info__goBack"><span><i className="fa fa-angle-left" /> BACK TO MAIN</span></div></Link>
{loading? <Loading />
: error? <MessageBox variant="danger">{error}</MessageBox>
:(<div className="info__content">
<div className="info__main">
<div className="info__imageBox">
<img src={showImage} className="info__image" alt={product.name}/>
<div className="info__imageCarousel">
{renderImages}
</div>
</div>
<div className="info__description">
<h2>{product.name}</h2>
<div className="info__ratings row">
<ReactStars
count={5}
value={product.rating}
size={15}
activeColor="yellow"
edit={false}
/>
<span> {product.numReviews + (product.numReviews>0? " reviews" : " review")}</span>
</div>
<h3>${product.price}</h3>
<h4><span className="head">Materials </span> {product.material}</h4>
<h4><span className="head">Description </span> {product.description}</h4>
</div>
</div>
<div className="info__action">
<div className="info__seller row">
<h3>Seller</h3>
<h3>{seller.name}</h3>
</div>
<div className="info__ratings row" style={{paddingLeft:0}}>
<ReactStars
count={5}
value={product.rating}
size={15}
activeColor="yellow"
edit={false}
/>
<h3> {product.numReviews + (product.numReviews>0? " reviews" : " review")}</h3>
</div>
<div className="row">
<h3>Price</h3>
<h3>${product.price}</h3>
</div>
<div className="row">
<h3>Status</h3>
<h3>{product.countInStock > 5 ? (<span className="">In Stock</span>) : product.countInStock > 0? (<span className="red">Only {product.countInStock} In Stock</span>): (<span className="red">Unavailable</span>)}</h3>
</div>
<div className="row" style={{margin: '2rem 0'}}>
<label for="qty">Qty</label>
<select name="qty" style={{color: 'black',fontSize:"1.8rem",height: '2.9rem',padding: '3px 10px'}} >
<option >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>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</div>
<div className="row center">
<button className="">ADD TO CART</button>
</div>
</div>
</div>)}
</div>
)
}
export default ProductInfo;
==========
错误消息:未捕获的类型错误:无法读取未定义的属性“sellerId”
解决方法
我认为这里可能存在一些问题。但这是我注意到的。
- 当你从后端获取数据时,你必须为 Axios 指定完整的 url。否则,它将尝试从当前 url 中获取它。因此,需要更改此代码以包含完整的后端网址:
从这里:
const { data } = await Axios.get('/api/products');
这样的事情:
const { data } = await Axios.get('https://my-backend.com/api/products');
对后端的其他调用也是如此。
- 在您的
ProductInfo
组件中,您试图从产品对象中获取 id。但是这个变量不存在。我认为您的意思是productDetails
或直接使用productId
const seller = SELLERS.find((seller) => seller._id === product.sellerId);