我在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 });
};
答案 0 :(得分:1)
在React中,不允许对象突变,并且每次都必须创建一个新的对象副本。
existingProduct.quantity++;
应该是
const newProduct = {...existingProduct, quantity: existingProduct.quantity + 1}
this.setState((state) => ({
products: state.products
}));
类似的问题,您应该创建一个数组的新实例。
答案 1 :(得分:0)
像这样的用户界面修改AddToProducts之后,再次正确地重新渲染:
AddToProducts(newProduct) {
var newProductList = this.state.products.slice();
const productIndex = newProductList.findIndex(item => item.id === newProduct.id);
newProductList[productIndex].quantity = newProductList[productIndex].quantity + 1;
this.setState({ products: newProductList });
}
我不确定为什么这不起作用(immerjs):
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 });
}