【发布时间】:2021-03-19 00:40:46
【问题描述】:
正在获取显示产品规格的产品详细信息视图页面,但该组件的视图未显示。它读取正确的路径和产品 ID,因为它显示在 URL 上,但页面本身是空白的。
我认为我的错误是在 PageLayout 部分,但我已经多次重做好几天了,但没有运气。
APP.js:
import React, { Fragment, useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import NavbarMain from "./components/pagelayout/Navbar/Navbar";
import Footer from "./components/pagelayout/Footer/Footer";
import HomePage from "./components/landingpage/page/HomePage";
import setAuthToken from "./utilities/setAuthToken";
import Login from "./components/auth/Login";
import Register from "./components/auth/Register";
import AccountPage from "./components/pers_account/AccountPage";
import OurStory from "./components/story/OurStory";
import SustainableCode from "./components/sustcode/SustainableCode";
import AdminRoute from "./components/routing/AdminRoute";
import PrivateRoute from "./components/routing/PrivateRoute";
import ProductForm from "./components/forms/ProductForm/ProductForm";
import ProductDisplay from "./components/productdisplay/ProductDisplay";
import PageLayout from "./components/productdetails/layout/PageLayout";
import Alert from "./components/pagelayout/Alert/Alert";
//Redux
import { Provider } from "react-redux";
import store from "./store";
import { loadUser } from "./actions/auth";
if (localStorage.token) {
setAuthToken(localStorage.token);
}
const App = () => {
useEffect(() => {
store.dispatch(loadUser());
}, []);
return ( < Provider store = { store } >
<Router >
<Fragment >
<NavbarMain / >
<Route exact path = "/" component = { HomePage }/>
<br/>
<section className = "container">
<Alert/>
<Switch>
<Route exact path = "/products/items" component = {ProductDisplay}/>
<Route exact path = "/products/items/:id" component = {PageLayout} />
<Route exact path = "/account/login"component = { Login }/>
<Route exact path = "/account/register"component = { Register }/>
<PrivateRoute exact path="/account" component = {AccountPage}/>
<AdminRoute exact path = "/products/add/sustdrop" component = {ProductForm}/>
<Route exact path = "/sustdrop/story" component = { OurStory }/>
<Route exact path = "/sustdrop/sustainablecode" component = {SustainableCode}/>
</Switch>
</section>
<Footer/>
</Fragment>{" "}
</Router >
</Provider>
);
}
export default App;
Redux 操作:
import {
GET_PRODUCTS,
GET_PRODUCT,
PRODUCT_ERROR,
CLEAR_SELECTED_PRODUCT,
ADD_PRODUCT_SUCCESS,
DONE_LOADING_PRODUCTS,
DONE_DELETING_PRODUCTS,
} from "./types";
import axios from "axios";
import { setAlert } from "./alert";
// Get all products
export const getProducts = () => async(dispatch) => {
try {
const res = await axios.get("/api/products");
dispatch({
type: GET_PRODUCTS,
payload: res.data,
});
} catch (err) {
dispatch({
type: PRODUCT_ERROR,
payload: { msg: err.response.statusText, status: err.response.status },
});
}
};
// change 'loading' to true
export const doneLoading = () => async(dispatch) => {
dispatch({
type: DONE_LOADING_PRODUCTS,
});
};
// Get a specific product by ID
export const getProduct = (id) => async(dispatch) => {
try {
const res = await axios.get(`/api/products/${id}`);
dispatch({
type: GET_PRODUCT,
payload: res.data,
});
} catch (err) {
dispatch({
type: PRODUCT_ERROR,
payload: {
status: err.response.status,
statusText: err.response.statusText,
},
});
}
};
// clears selected products
export const clearSelectedProduct = () => (dispatch) => {
dispatch({
type: CLEAR_SELECTED_PRODUCT,
});
};
// Add a product
export const addProduct = ({ formData }) => async(dispatch) => {
const config = {
headers: {
"Content-Type": "application/json",
},
};
try {
const res = await axios.post("/api/products", formData, config);
dispatch({
type: ADD_PRODUCT_SUCCESS,
});
dispatch(setAlert(res.data.msg, "success"));
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, "danger")));
}
}
};
// Delete selected product
export const deleteProducts = (products_id) => async(dispatch) => {
try {
const res = await axios.delete(`/api/products/${products_id}`);
dispatch({
type: CLEAR_SELECTED_PRODUCT,
});
dispatch({
type: DONE_DELETING_PRODUCTS,
});
dispatch(setAlert(res.data.msg, "success"));
} catch (err) {
dispatch({
type: PRODUCT_ERROR,
payload: { msg: err.response.statusText, status: err.response.status },
});
}
};
Redux 减速器:
import {
GET_PRODUCTS,
GET_PRODUCT,
PRODUCT_ERROR,
CLEAR_SELECTED_PRODUCT,
ADD_PRODUCT_SUCCESS,
DONE_LOADING_PRODUCTS,
DONE_DELETING_PRODUCTS,
} from "../actions/types";
const initialState = {
selectedProduct: null, // latest product you clicked
products: [], // all the products
loadingProducts: true,
error: null,
loadingSelectedProduct: true,
isAddingProductsSuccessful: false,
deletingProducts: false,
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case GET_PRODUCTS:
return {
...state,
products: payload,
loadingProducts: false,
isAddingProductsSuccessful: false,
deletingProducts: false,
};
case DONE_LOADING_PRODUCTS:
return {
...state,
loadingProducts: true,
};
case GET_PRODUCT:
return {
...state,
selectedProduct: payload,
loadingSelectedProduct: false,
};
case CLEAR_SELECTED_PRODUCT:
return {
...state,
selectedProduct: null,
loadingSelectedProduct: false,
};
case ADD_PRODUCT_SUCCESS:
return {
...state,
isAddingProductsSuccessful: true,
};
case PRODUCT_ERROR:
return {
...state,
error: payload,
};
case DONE_DELETING_PRODUCTS:
return {
...state,
deletingProducts: true,
};
default:
return state;
}
}
产品详情文件夹:
Details.js
import React, { useState } from 'react';
import { withRouter } from "react-router-dom";
// CSS \\
import "./ProductDetails.css";
const ProductDetails = (props) => {
const { _id, brand, name, description, retail_price} = props.selectedProduct;
const { deleteProducts } = props;
return (
<div className = "details-wrapper">
<div className = "product-info">
<h1 className = "product-info-brand">{brand}</h1>
<p className = "product-info-name">{name}</p>
<p className = "product-info-desc">{description}</p>
<p className = "product-info-price"> retail price: {retail_price}</p>
</div>
{
props.isAdmin ? (
<>
<button className = "productinfo-button btn btn-danger btn-block btn-sm"
onClick = {() => deleteProducts(_id)}>Delete Product</button>
</>
) : null
}
</div>
);
};
export default withRouter(ProductDetails);
产品图片显示规格:
import React, { useState } from "react";
// CSS \\
import "./Images.css";
const Images = (props) => {
const { images } = props;
const [mainImage, setMainImage] = useState(images[0]);
const changeMainImage = (image) => {
setMainImage(image);
};
return (
<div className = "image-wrapper" >
<div className = "mainrow" >
<img src = { mainImage } alt = "mainproduct" />
</div>
<div className = "alt-images" >
<div className = "secondrow" >
{images.map((productImage, index) => (
<div key = { index } className = "alternativepics" onClick = {() => changeMainImage(productImage) }>
<img src = { productImage } alt = "small_alts" / >
</div>
))
}
</div>
</div>
</div>
);
};
export default Images;
最重要的,详细的页面布局:
layout.js
import React, { useEffect, Fragment } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { Redirect } from "react-router-dom";
import { getProducts, getProduct, clearSelectedProduct, deleteProducts } from "../../../actions/product";
import Loading from "../../pagelayout/Loading/Loading";
import ProductDetails from "../details/ProductDetails";
import Images from "../images/Images";
const PageLayout = ({
getProduct, getProducts, clearSelectedProduct, deleteProducts, match : {
params: { id },
},
product: { selectedProduct, products, deletingProducts, error },
auth: { isAdmin },
}) => {
useEffect(() => {
selectProduct(id);
getProduct();
}, []);
const selectProduct = (id) => {
clearSelectedProduct();
getProduct(id);
};
if(deletingProducts){
return <Redirect to = { "/"}/>;
};
return selectedProduct === null ? (
error ? (
<div>
<p>{error.msg}</p>
</div>
) : (<Loading/> )
) : (
<Fragment>
<Images images = { selectedProduct.images}/>
<ProductDetails selectedProduct = {selectedProduct} isAdmin = {isAdmin} deleteProducts = {deleteProducts}/>
</Fragment>
);
};
const mapStateToProps = (state) => ({
product: state.product,
auth: state.auth,
});
PageLayout.propTypes= {
getProduct: PropTypes.func,
getProducts: PropTypes.func,
clearSelectedProduct: PropTypes.func,
deleteProducts: PropTypes.func,
product: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired
};
export default connect(mapStateToProps, {
getProduct, getProducts, clearSelectedProduct, deleteProducts
})(PageLayout);
【问题讨论】:
-
您好,您将最后一个文件称为
layout.js,我们可以假设它的全名确实是./components/productdetails/layout/PageLayout.js,并且您没有引用另一个文件吗? -
我很抱歉文件名实际上是 PageLayout.js 而不仅仅是 layout.js。文件路径正确
标签: reactjs redirect redux routes