Я делаю первое приложение в Reactjs (простой магазин), и у меня есть некоторые проблемы с повторным отображением пользовательского интерфейса после изменения значений состояния. Все работало правильно, прежде чем использовать PrivateRoute внутри App.js. Теперь, когда я нажимаю «Добавить на карту», состояние продукта меняется, как и должно быть (количество установлено на 1), но в интерфейсе пользователя оно по-прежнему равно 0 (поэтому компонент не отображается повторно).
Может быть, это потому, что я использую component = {ProductList} вместо render = {() =>} внутри маршрутизации App.js. Но рендер больше не работает с PrivateRoute (выдаются ошибки). Я не уверен, что я делаю неправильно, но, к сожалению, это мои первые дни, когда я пишу что-то в реагировании, поэтому мне нужна небольшая помощь.
![enter image description here](https://i.stack.imgur.com/H5Qgw.png)
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);
}} />
);
}
Раньше (когда все работало идеально), я не использовал PrivateRoute внутри App.js. Маршрут к моему списку товаров выглядел так:
<Route exact path="/" render={() => <ProductList products={this.state.products} selectProductHandler={this.AddItemToSelectedProductList} />} />
После предложений @Sky я изменил реализацию 'add to card'. Я использовал immerjs, чтобы сделать это просто. После всех изменений все работает как прежде, пользовательский интерфейс не перерисовывается. Здесь изменен код:
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 });
};