I'm using React Router 4.
I have a ShopCoffee component which allows to add items to Cart.
By clicking Cart LINK React renders Cart component.
Without Router (when Cart component is on the same page as main app), Cart works fine.
But another Cart component (which is attached to the router) doesn't recieve props, so the Cart renders as empty.
If I click LINK to Cart (cart icon) one more time, it rerenders and shows all items.
So, if I render component like this:
<Cart itemsInCart = {this.state.itemsInCart} deleteItemFromCart = {this.deleteItemFromCart} />
it works correctly,
but when I do this:
const CartRoute = (props) => (<Cart itemsInCart = {this.state.itemsInCart} deleteItemFromCart = {this.deleteItemFromCart} {...props} />);
it works only if I click twice on LINK tag.
Here is the code:
app.jsx
import React from "react";
import ReactDOM from "react-dom";
import Main from "./components/main.component.jsx";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { BrowserRouter, Route } from "react-router-dom";
var app = document.getElementById("app");
function mainAppReducer(state, action) {
if (!state) return {
items: []
}
switch (action.type) {
case 'ADD_TO_CART' : console.log('ADD_TO_CART');
console.log("action.items == ", action.items);
console.log("state==",state);
return Object.assign({}, action.items); // state уже содержит все данные об объектах в корзине, поэтому ничего не добавляем
case 'DELETE_FROM_CART' : console.log('DELETE_FROM_CART');
console.log("action.items == ", action.items);
console.log("state==",state);
return Object.assign({}, action.items); // state уже содержит все данные об объектах в корзине, поэтому ничего не добавляем
}
}
const store = createStore(mainAppReducer);
var render = () => ReactDOM.render(
<BrowserRouter>
<Provider store={store}>
<Route path="/" component = {Main} />
</Provider>
</BrowserRouter>
, app);
store.subscribe(render);
render();
main.component.jsx
import React from "react";
import Header from "./header.component.jsx";
import Footer from "./footer.component.jsx";
import Cart from "./cart.component.jsx";
import Checkout from "./checkout.component.jsx";
import ShopCoffee from "./shop-coffee.component.jsx";
import Rent from "./rent.component.jsx";
import Repair from "./repair.component.jsx";
import Contacts from "./contacts.component.jsx";
import ToCartButton from "./to-cart-button.component.jsx";
import { connect } from "react-redux";
import { Route, Switch } from "react-router-dom";
export class Main extends React.Component {
constructor(props) {
super(props);
this.addNewItemToCart = this.addNewItemToCart.bind(this);
this.deleteItemFromCart = this.deleteItemFromCart.bind(this);
this.state = {itemsInCart : []};
}
addNewItemToCart(itemsInCart) {
this.props.dispatch({type : 'ADD_TO_CART',
items: itemsInCart});
this.setState({itemsInCart : itemsInCart});
console.log("this.state", this.state);
}
deleteItemFromCart(i) {
var itemToDelete = this.state.itemsInCart[i];
console.log("itemToDelete == ", itemToDelete);
var itemsLeft = this.state.itemsInCart.filter((x,ind) => ind != i);
this.props.dispatch({type : 'DELETE_FROM_CART',
items: itemsLeft});
console.log("itemsLeft == ", itemsLeft);
this.setState({itemsInCart: itemsLeft});
}
getItemsInCart(itemsInCart) {
return itemsInCart;
}
render() {
const ShopCoffeeRoute = (props) => (<ShopCoffee itemsInCart = {this.state.itemsInCart} addNewItemToCart = {this.addNewItemToCart} {...props} />);
const CartRoute = (props) => (<Cart itemsInCart = {this.state.itemsInCart} deleteItemFromCart = {this.deleteItemFromCart} {...props} />);
const CheckoutRoute = (props) => (<Checkout itemsInCart = {this.state.itemsInCart} {...props} />);
return (
<main>
<Header />
<Switch>
<Route exact path="/" render={ShopCoffeeRoute} />
<Route path="/rent" component={Rent} />
<Route path="/repair" component={Repair} />
<Route path="/contacts" component={Contacts} />
<Route path="/checkout" render={CheckoutRoute} />
<Route path="/cart" render={CartRoute} />
</Switch>
<Cart itemsInCart = {this.state.itemsInCart} deleteItemFromCart = {this.deleteItemFromCart} />
<ToCartButton itemsInCart = {this.state.itemsInCart} />
<Footer />
</main>
);
}
}
export default connect((store) => store)(Main);
to-cart-button.component.jsx
import React from 'react';
import { Link } from "react-router-dom";
export default class ToCartButton extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Link to="/cart">
<section className="to-cart-button">
<div className="to-cart-button__text-container">
<p className="to-cart-button__text-container__text">
{this.props.itemsInCart.length}
</p>
</div>
</section>
</Link>
);
}
}
cart.component.jsx
import React from "react";
import { Link } from "react-router-dom";
export default class Cart extends React.Component {
constructor(props) {
super(props);
this.state = {itemsInCart : []};
}
componentWillReceiveProps(nextProps) {
if (nextProps.itemsInCart != this.state.itemsInCart) {
this.setState({itemsInCart : nextProps.itemsInCart});
}
}
deleteItemFromCart(i) {
var itemsLeft = this.state.itemsInCart.filter((x,ind) => ind != i);
this.props.deleteItemFromCart(i);
console.log("itemsLeft === ", itemsLeft);
this.setState({itemsInCart : itemsLeft});
}
render() {
console.log("Cart /");
console.log("this.props == ",this.props);
var imgPath = "img/coffee/"
var itemsInTable;
var itemsInCart = this.state.itemsInCart;
var totalPrice = 0;
if (!itemsInCart.length) {
itemsInTable = (<tr>
<td colSpan="5">Ваша корзина пуста</td>
</tr>);
}
else {
totalPrice = 0;
itemsInTable = (itemsInCart.map((item, i) => {
totalPrice += +item.price;
console.log("totalPrice==",totalPrice);
return (
<tr key={i}>
<td>{item.title}</td>
<td><img src={imgPath + item.image} /></td>
<td>1 шт.</td>
<td>{item.price} руб.</td>
<td><button className="cart__table__delete-button" onClick={this.deleteItemFromCart.bind(this, i)}><i className="fa fa-times"></i></button></td>
</tr>);
}));
}
return (
<section className="cart">
<div className="container">
<div className="row">
<div className="cart__title-container">
<h2 className="cart__title-container__title">
Ваша корзина
</h2>
</div>
</div>
<div className="row">
<div className="col-md-12">
<table className="cart__table">
<tbody>
<tr>
<th colSpan="5">Список товаров</th>
</tr>
{itemsInTable}
<tr>
<td></td>
<td></td>
<td>Итого:</td>
<td>{totalPrice} руб.</td>
<td></td>
</tr>
</tbody>
</table>
<div className="cart__next-button-container">
<Link to="/checkout"><button className="cart__next-button">Далее >></button></Link>
</div>
</div>
</div>
</div>
</section>
);
}
}