Integrated redux now 產品不再顯示。我嘗試添加一個條件,例如"{products && products.map((product) => ..")
. 空白頁消失,但仍然沒有產品。錯誤也消失了。在 redux devTools 我得到:
{
type: 'PRODUCT_LIST_SUCCESS',
payload: [
{
_id: 1,
name: 'IPhone 11 Pro 256GB memory',
image: '/images/phone.jpg',
brand: 'Apple',
category: 'Electronics',
description: 'Bluetooth technology lets you connect it with compatible devices wirelessly High-Quality AAC audio offers immense experience Built-in microphone allows you take calls while working',
rating: '4.00',
numReviews: 8,
price: '599.99',
countInStock: 7,
created: '2022-11-14T18:29:17.417487Z',
user: 1
},
]
}
商店.js:
import {
legacy_createStore as createStore,
combineReducers,
applyMiddleware,
} from "redux";
//import { configureStore } from "@reduxjs/toolkit";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import {
productListReducers,
productDetailsReducers,
} from "./reducers/ProductReducers";
const reducer = combineReducers({
productList: productListReducers,
productDetails: productDetailsReducers,
});
const initialState = {};
const middleware = [thunk];
const store = createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
應用程式.js:
import "./App.css";
import "./index.css";
import { Container } from "react-bootstrap";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Footer from "./components/Footer";
import Header from "./components/Header";
import HomeScreen from "./components/screens/HomeScreen";
import ProductScreen from "./components/screens/ProductScreen";
function App() {
return (
<Router>
<Header />
<main className="my-3">
<Container>
<Routes>
<Route path="/" element={<HomeScreen />} />
<Route path="/product/:id" element={<ProductScreen />} />
</Routes>
</Container>
</main>
<Footer />
</Router>
);
}
export default App;
主螢屏.js:
import React, { useState, useEffect } from "react";
//import products from "../../products";
import { Row, Col } from "react-bootstrap";
import Product from "../Product";
import { useDispatch, useSelector } from "react-redux";
import { listProducts } from "../../actions/ProductAction";
import Message from "../Message";
import Loader from "../Loader";
function HomeScreen() {
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { error, loading, products } = productList;
useEffect(() => {
dispatch(listProducts());
}, [dispatch]);
return (
<div>
<h1 className="text-center">Latest Products</h1>
{loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<Row>
{products &&
products.map((product) => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
{/* <h3>{product.name}</h3> */}
<Product product={product} />
</Col>
))}
</Row>
)}
</div>
);
}
export default HomeScreen;
ProductScreen.js:
import React, { useState, useEffect } from "react";
import { Link, useParams } from "react-router-dom";
import { Row, Col, Image, ListGroup, Button, Card } from "react-bootstrap";
//import products from "../../products";
import Rating from "../Rating";
import { useDispatch, useSelector } from "react-redux";
import Message from "../Message";
import Loader from "../Loader";
import { listProductDetails } from "../../actions/ProductAction";
import { productDetailsReducers } from "../../reducers/ProductReducers";
function ProductScreen() {
const [quantity, setQuantity] = useState(1);
const { id } = useParams();
const dispatch = useDispatch();
const productDetails = useSelector((state) => state.productDetails);
const { loading, error, product } = productDetails;
useEffect(() => {
async function fetchProduct() {
if (id) {
dispatch(listProductDetails(id));
}
}
fetchProduct();
}, [dispatch, id]);
return (
<div>
<Link to="/" className="btn btn-dark my-3">
Go Back
</Link>
{loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<Row>
<Col md={6}>
<Image
className="imgCustom"
src={product.image}
alt={product.name}
></Image>
</Col>
<Col md={3}>
<ListGroup variant="flush">
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating
value={product.rating}
text={`${product.numReviews} reviews`}
color={"f8e825"}
/>
</ListGroup.Item>
<ListGroup.Item>Price : ${product.price}</ListGroup.Item>
<ListGroup.Item>
Description: ${product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<Row>
<Col>Price : </Col>
<Col>
<strong>$ {product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Status : </Col>
<Col>
{product.countInStock > 0 ? "In Stock" : "Out of Stock"}
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Button
className="btn-block"
disabled={product.countInStock === 0}
type="button"
>
Add to Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
)}
</div>
);
}
export default ProductScreen;
ProductAction.js:
import axios from "axios";
import {
PRODUCT_LIST_REQUEST,
PRODUCT_LIST_SUCCESS,
PRODUCT_LIST_FAIL,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
} from "../constants/ProductConstants";
export const listProducts = () => async (dispatch) => {
try {
dispatch({ type: PRODUCT_LIST_REQUEST });
const { data } = await axios.get("/api/products/");
dispatch({
type: PRODUCT_LIST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: PRODUCT_LIST_FAIL,
payload:
error.response && error.response.data.detail
? error.response.data.detail
: error.message,
});
}
};
export const listProductDetails = (id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILS_REQUEST });
const { data } = await axios.get(`/api/products${id}`);
dispatch({
type: PRODUCT_DETAILS_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILS_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
ProductReducers.js:
import {
PRODUCT_LIST_REQUEST,
PRODUCT_LIST_SUCCESS,
PRODUCT_LIST_FAIL,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
} from "../constants/ProductConstants";
export const productListReducers = (state = { products: [] }, action) => {
switch (action.type) {
case PRODUCT_LIST_REQUEST:
return { loading: true, product: [] };
case PRODUCT_LIST_SUCCESS:
return { loading: false, product: [action.payload] };
case PRODUCT_LIST_FAIL:
return { loading: true, product: [action.payload] };
default:
return state;
}
};
export const productDetailsReducers = (state = {product:{ reviews: [] }}, action) => {
switch (action.type) {
case PRODUCT_DETAILS_REQUEST:
return { loading: true, ...state };
case PRODUCT_DETAILS_SUCCESS:
return { loading: false, product: [action.payload] };
case PRODUCT_DETAILS_FAIL:
return { loading: true, product: [action.payload] };
default:
return state;
}
};
uj5u.com熱心網友回復:
問題
狀態至少更新一次后,組件似乎HomeScreen
正在選擇products
redux store 狀態切片中不存在的屬性。
主螢屏
function HomeScreen() {
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { error, loading, products } = productList; // <-- products
Redux store 的組合減速器
const reducer = combineReducers({
productList: productListReducers,
productDetails: productDetailsReducers,
});
productListReducers
這里的 reducer 案例都沒有保持products
陣列狀態不變,它們每個都更改/回傳一個product
屬性。
export const productListReducers = (state = { products: [] }, action) => {
switch (action.type) {
case PRODUCT_LIST_REQUEST:
return { loading: true, product: [] };
case PRODUCT_LIST_SUCCESS:
return {
loading: false,
product: [action.payload] // <-- product, not products
};
case PRODUCT_LIST_FAIL:
return { loading: true, product: [action.payload] };
default:
return state;
}
};
此外,該操作PRODUCT_LIST_SUCCESS
似乎回傳一個產品陣列的有效負載。
{
type: 'PRODUCT_LIST_SUCCESS',
payload: [
{
_id: 1,
name: 'IPhone 11 Pro 256GB memory',
image: '/images/phone.jpg',
brand: 'Apple',
category: 'Electronics',
description: 'Bluetooth technology lets you connect it with compatible devices wirelessly High-Quality AAC audio offers immense experience Built-in microphone allows you take calls while working',
rating: '4.00',
numReviews: 8,
price: '599.99',
countInStock: 7,
created: '2022-11-14T18:29:17.417487Z',
user: 1
},
]
}
return { loading: false, product: [action.payload] };
會導致在一個陣列中嵌套一個陣列,這可能不是預期的結果。
解決方案
保持products
屬性狀態不變并將products
狀態設定為 的值action.payload
。您很可能還想清除products
陣列并在失敗的情況下設定一些錯誤狀態。
export const productListReducers = (state = { products: [] }, action) => {
switch (action.type) {
case PRODUCT_LIST_REQUEST:
return { loading: true, products: [] };
case PRODUCT_LIST_SUCCESS:
return { loading: false, products: action.payload };
case PRODUCT_LIST_FAIL:
return {
loading: false, // <-- clear loading state
products: [], // <-- empty products array
error: action.payload, // <-- set error state
};
default:
return state;
}
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/533615.html
上一篇:根據日期差異更改顏色-React