【发布时间】:2019-06-13 07:53:05
【问题描述】:
我正在 Reactjs(简单商店)中制作第一个应用程序,并且在更改状态值后重新渲染 UI 时遇到了一些问题。在 App.js 中使用 PrivateRoute 之前一切正常。现在,当我单击“添加到卡”时,产品状态会发生应有的变化(数量设置为 1),但在 UI 上它仍然为 0(因此不会重新渲染组件)。 也许是因为我在 App.js 路由中使用 component={ProductList} 而不是 render={() => } 。但是渲染不再适用于 PrivateRoute(抛出错误)。我不确定我做错了什么,但我很伤心,这是我在 reactjs 中写任何东西的第一天,所以我需要一点帮助。
App.js
import React from 'react';
import './../App.css';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Navbar from '../components/navbar';
import ProductList from '../components/productList';
import Checkout from '../components/checkout';
import Payment from '../components/payment';
import Footer from '../components/footer';
import SignIn from '../components/auth/signIn';
import SignUp from '../components/auth/signUp';
import { PrivateRoute } from '../components/auth/privateRoute';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loggedIn: true,
selectedProducts: [],
products: [
{
"id": 1,
"name": "11 bit studios SA",
"grossPrice": 390.00,
"netPrice": 360.00,
"image": "https://jarock.pl/upload/posts/836323184026f846637c9e455b3950a4.jpg",
"description": "",
"quantity": 0
},
{
"id": 2,
"name": "PEKAO",
"grossPrice": 108.00,
"netPrice": 100.00,
"image": "https://pbs.twimg.com/profile_images/1107386368609652736/U91cV_vU.png",
"description": "",
"quantity": 0
},
{
"id": 3,
"name": "CDPROJEKT",
"grossPrice": 198.00,
"netPrice": 170.00,
"image": "https://yt3.ggpht.com/a/AGF-l7_JugJ8uDvDTXqsBPLuT4ZueARyKoM1dVG1gA=s900-mo-c-c0xffffffff-rj-k-no",
"description": "",
"quantity": 0
},
{
"id": 4,
"name": "CCC",
"grossPrice": 147.00,
"netPrice": 135.00,
"image": "https://ccc.eu/start_page/assets/img/logo.jpg",
"description": "",
"quantity": 0
}
]
}
this.AddItemToSelectedProductList = this.AddItemToSelectedProductList.bind(this);
this.RemoveItemFromSelectedProductList = this.RemoveItemFromSelectedProductList.bind(this);
}
AddItemToSelectedProductList(newProduct) {
var newProductList = this.state.selectedProducts;
const existingProduct = newProductList.find(item => newProduct.id === item.id);
if (existingProduct) {
existingProduct.quantity++;
this.setState((state) => ({
products: state.products
}));
}
else {
newProduct.quantity = 1;
newProductList.push(newProduct);
this.setState({ selectedProducts: newProductList });
}
};
RemoveItemFromSelectedProductList(productToRemove) {
var newProductList = this.state.selectedProducts;
if (newProductList.length > 0) {
const productToRemoveIndex = newProductList.indexOf(productToRemove);
newProductList.splice(productToRemoveIndex, 1);
this.setState({ selectedProducts: newProductList });
}
var displayedProductList = this.state.products;
const displayedProduct = displayedProductList.find(x => x.id === productToRemove.id);
displayedProduct.quantity = 0;
this.setState({ products: displayedProductList });
};
render() {
return (
<Router>
<div className="main-div">
<Navbar checkoutItems={this.state.selectedProducts} />
<PrivateRoute exact path='/' component={ProductList} products={this.state.products} selectProductHandler={this.AddItemToSelectedProductList} />
<PrivateRoute path="/checkout" component={Checkout} selectedProducts={this.state.selectedProducts} removeProductHandler={this.RemoveItemFromSelectedProductList} />
<PrivateRoute path="/payment" component={Payment} />
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</div>
<Footer />
</Router>
);
}
}
export default App;
PrivateRoute.js
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
export const PrivateRoute = ({ component, redirectTo, ...rest }) => {
return (
<Route {...rest} render={routeProps => {
return localStorage.getItem('user') ? (
renderMergedProps(component, routeProps, rest)
) : (
<Redirect to={{
pathname: '/signin',
state: { from: routeProps.location }
}} />
);
}} />
);
};
const renderMergedProps = (component, ...rest) => {
const finalProps = Object.assign({}, ...rest);
return (
React.createElement(component, finalProps)
);
}
export const PropsRoute = ({ component, ...rest }) => {
return (
<Route {...rest} render={routeProps => {
return renderMergedProps(component, routeProps, rest);
}} />
);
}
之前(当一切正常时)我没有在 App.js 中使用 PrivateRoute。我的产品列表的路径如下所示:
<Route exact path="/" render={() => <ProductList products={this.state.products} selectProductHandler={this.AddItemToSelectedProductList} />} />
在@Sky 提出建议后,我更改了“添加到卡片”的实现。我使用 immerjs 来简化它。在所有更改之后一切都像以前一样工作,UI 不会重新渲染。这是更改的代码:
AddItemToSelectedProductList(newProduct) {
this.AddToSelectedProducts(newProduct);
this.AddToProducts(newProduct);
};
AddToProducts(newProduct) {
const nextState = produce(this.state.products, draft => {
const productIndex = draft.findIndex(item => item.id === newProduct.id);
draft[productIndex].quantity = draft[productIndex].quantity + 1;
});
this.setState({ products: nextState });
}
AddToSelectedProducts(newProduct) {
var newProductList = this.state.selectedProducts;
const existingProduct = newProductList.find(item => newProduct.id === item.id);
var nextState = [];
if (existingProduct) {
nextState = produce(newProductList, draft => {
const existingProductIndex = draft.findIndex(item => item.id === newProduct.id);
draft[existingProductIndex].quantity = draft[existingProductIndex].quantity + 1;
});
}
else {
const nextProductState = produce(newProduct, draft => {
draft.quantity = 1;
});
nextState = produce(newProductList, draft => {
draft.push(nextProductState);
});
}
this.setState({ selectedProducts: nextState });
};
【问题讨论】: