mapStateToProps is not getting called in redux, state is not defined - javascript

App.js
import React, { Component } from "react";
import "./App.css";
import Router from "./Router";
class App extends Component {
render() {
return (
<div className="App">
<div>
<h1>React-Redux Store</h1>
<h2>Welcome to the React Store</h2>
</div>
<Router />
</div>
);
}
}
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import "bootstrap/dist/css/bootstrap.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducer from "./reducer";
import "../node_modules/font-awesome/css/font-awesome.min.css";
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
ShopHome.js
when i open the page, it appears TypeError: Cannot read property 'items' of undefined, I guess its something wrong with mapStateToProps and cannot define the state. i Wonder if i did something wrong in the reducer
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
import { connect } from "react-redux";
import { addToCart } from "./action_type";
class ShopHome extends Component {
handleClick = id => {
this.props.addToCart(id);
};
render() {
return (
<div>
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>
<NavLink to="/myCart" exact activeStyle={{ color: "green" }}>
my cart
</NavLink>
</th>
</tr>
</thead>
<tbody>
{this.props.items.map(item => {
return (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.description}</td>
<td>${item.price}</td>
<button to="/" onClick={() => this.handleClick(item.id)}>
add to cart
</button>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
const mapStateToProps = state => {
return {
items: state.items
};
};
const mapDispatchToProps = dispatch => {
return {
addToCart: id => {
dispatch(addToCart(id));
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ShopHome);
ShopCart.js
when i add the add quantity functionality it all works fine, but however after i added subtract quantity functionality it turns out says state is not defined(
TypeError: Cannot read property 'items' of undefined
Function.mapStateToProps [as mapToProps]
src/shopHome.js:47
44 | }
45 | const mapStateToProps = state => {
46 | return {
> 47 | items: state.items
48 | };
49 | };
50 | )
ShopCart.js
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
import { connect } from "react-redux";
import { addQuantity } from "./action_type";
import { subtractQuantity } from "./action_type";
class ShopCart extends Component {
handleAddQuantity = id => {
this.props.addQuantity(id);
};
handleSubtractQuantity = id => {
this.props.subtractQuantity(id);
};
render() {
let addedItems = this.props.items.map(item => {
return (
<tr key={item.id}>
<td>{item.name}</td>
<td>
<NavLink to="/myCart">
<span>
<i
className="fas fa-plus-circle"
onClick={() => {
this.handleAddQuantity(item.id);
}}
></i>
</span>
</NavLink>
{item.quantity}
<NavLink to="/myCart">
<span>
<i
className="fas fa-minus-circle"
onClick={() => {
this.handleSubtractQuantity(item.id);
}}
></i>
</span>
</NavLink>
</td>
<td>${item.price}</td>
</tr>
);
});
return (
<div>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>
<NavLink to="/" exact activeStyle={{ color: "green" }}>
back to store
</NavLink>
</th>
</tr>
</thead>
<tbody>{addedItems}</tbody>
</table>
</div>
);
}
}
const mapStateToProps = state => {
return {
items: state.addedItems
};
};
const mapDispatchToProps = dispatch => {
return {
addQuantity: id => dispatch(addQuantity(id)),
subtractQuantity: id => dispatch(subtractQuantity(id))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ShopCart);
reducer.js
import { ADD_TO_CART, ADD_QUANTITY, SUBTRACT_QUANTITY } from "./action.js";
const initialState = {
items: [
{
id: 1,
name: "apple",
description: "Eat One Every Day, may keep the doctor away",
price: 12
},
{
id: 2,
name: "grape",
description: "Wine is great, but grapes is better",
price: 11
},
{
id: 3,
name: "pineapple",
description: "enjoy but don`t forget to peer first",
price: 8
}
],
addedItems: []
};
const reducer = (state = initialState, action) => {
if (action.type === ADD_TO_CART) {
let addedItem = state.items.find(item => item.id === action.id);
let existed_item = state.addedItems.find(item => item.id === action.id);
if (existed_item) {
addedItem.quantity += 1;
return {
...state
};
} else {
addedItem.quantity = 1;
return {
...state,
addedItems: [...state.addedItems, addedItem]
};
}
}
if (action.type === ADD_QUANTITY) {
let addedItem = state.items.find(item => item.id === action.id);
addedItem.quantity += 1;
return {
...state
};
}
if (action.type === SUBTRACT_QUANTITY) {
let addedItem = state.items.find(item => item.id === action.id);
if (addedItem.quantity === 1) {
let newItem = state.addedItems.filter(item => item.id !== action.id);
return {
...state,
addedItems: newItem
};
} else {
addedItem.quantity -= 1;
return {
...state
};
}
}
};
export default reducer;
action_type.js
import { ADD_TO_CART, ADD_QUANTITY, SUBTRACT_QUANTITY } from "./action";
export const addToCart = id => {
return {
type: ADD_TO_CART,
id
};
};
export const addQuantity = id => {
return {
type: ADD_QUANTITY,
id
};
};
export const subtractQuantity = id => {
return {
type: SUBTRACT_QUANTITY,
id
};
};
action.js
export const ADD_TO_CART = "ADD_TO_CART";
export const ADD_QUANTITY = "ADD_QUANTITY";
export const SUBTRACT_QUANTITY = "SUBTRACT_QUANTITY";
Hi everyone, I am new to react-redux, when i open the page, the page keep telling me that TypeError: Cannot read property 'items' of undefined in the ShopHome.js, i supppose its something wrong with declaring the state in the mapStateToProps function. can someone give me a hand?

Related

why my shopping cart not re-render after the change the state of the product

index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import "bootstrap/dist/css/bootstrap.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducer from "./reducer";
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
App.js
import React, { Component } from "react";
import "./App.css";
import Router from "./Router";
class App extends Component {
render() {
return (
<div className="App">
<div>
<h1>React-Redux Store</h1>
<h2>Welcome to the React Store</h2>
</div>
<Router />
</div>
);
}
}
export default App;
ShopHome.js
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
import { connect } from "react-redux";
import { addToCart } from "./action_type";
class ShopHome extends Component {
render() {
return (
<div>
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>
<NavLink to="/myCart" exact activeStyle={{ color: "green" }}>
my cart
</NavLink>
</th>
</tr>
</thead>
<tbody>
{this.props.items.map(item => {
return (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.description}</td>
<td>${item.price}</td>
<button onClick={this.props.addToCart(item.id)}>
add to cart
</button>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
const mapStateToProps = state => {
return {
items: state.items
};
};
const mapDispatchToProps = dispatch => {
return {
addToCart: id => {
dispatch(addToCart(id));
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ShopHome);
ShopCart.js
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
import { connect } from "react-redux";
import { addQuantity } from "./action_type";
class ShopCart extends Component {
render() {
let addedItems = this.props.items.map(item => {
return (
<tr key={item.id}>
<td>{item.name}</td>
<td>
<NavLink to="/myCart">
<i
class="glyphicon glyphicon-plus-sign"
onClick={this.props.addQuantity(item.id)}
></i>
{item.quantity}
<i
class="glyphicon glyphicon-minus-sign"
onClick={this.props.handleSubtractQuantity(item.id)}
></i>
</NavLink>
</td>
<td>${item.price}</td>
</tr>
);
});
return (
<div>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>
<NavLink to="/" exact activeStyle={{ color: "green" }}>
back to store
</NavLink>
</th>
</tr>
</thead>
<tbody>{addedItems}</tbody>
</table>
</div>
);
}
}
const mapStateToProps = state => {
return {
items: state.addedItems
};
};
const mapDispatchToProps = dispatch => {
return { addQuantity: id => dispatch(addQuantity(id)) };
};
export default connect(mapStateToProps, mapDispatchToProps)(ShopCart);
reducer.js
const initialState = {
items: [
{
id: 1,
name: "apple",
description: "Eat One Every Day, may keep the doctor away",
price: 12
},
{
id: 2,
name: "grape",
description: "Wine is great, but grapes is better",
price: 11
},
{
id: 3,
name: "pineapple",
description: "enjoy but don`t forget to peer first",
price: 8
}
],
addedItems: []
};
const reducer = (state = initialState, action) => {
if (action.type === "ADD_TO_CART") {
let addedItem = state.items.find(item => item.id === action.id);
let existed_item = state.addedItems;
if (existed_item) {
addedItem.quantity++;
} else {
addedItem.quantity = 1;
}
return {
...state,
addItems: [...state.addedItems, addedItem]
};
}
if (action.type === "ADD_QUANTITY") {
let addedItem = state.items.find(item => item.id === action.id);
addedItem.quantity++;
}
return {
...state
};
};
export default reducer;
action_type.js
export const addToCart = id => {
return {
type: "ADD_TO_CART",
id
};
};
export const addQuantity = id => {
return {
type: "ADD_QUANTITY",
id
};
};
Router.js
import React from "react";
import { Switch, Route } from "react-router-dom";
import ShopHome from "./shopHome";
import ShopCart from "./shopCart";
import { BrowserRouter } from "react-router-dom";
const Router = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={ShopHome} />
<Route exact path="/myCart" component={ShopCart} />
</Switch>
</BrowserRouter>
);
};
export default Router;
Hi everyone, I am new to react-redux, I am trying to setting up a shopping cart website, I have a main shopping cart page which host on localhost:3000, and once i pressed the my cart, will be route to /myCart, however, my problem is when i select the item and add to cart, and newest added item in the ShopCart component won't be rendered in my cart, I am not sure where i did wrong, can someone give me a hand?
I supposed ideally when i clicked the add to cart in the ShopHome.js, will trigger the addToCart function, then through the dispatcher, with action.type= "ADD_TO_CART" and id=item.id, then in the reducer, i want the quantity of selected item plus 1,However, when i pressed add to cart, and hit my cart, nothing is added.
First, you have a typo in your reducer.
addItems: [...state.addedItems, addedItem] It should be addedItems: [...state.addedItems, addedItem]
Next, you should rewrite the logic for ADD_TO_CART.
let existed_item = state.addedItems;
if (existed_item) {
addedItem.quantity++;
} else {
addedItem.quantity = 1;
}
You assigning existed_item to state.addedItems which is an array, so existed_item will always be true and it will try to increment a property that does exist.
Instead, change existed_item = state.addedItems to existed_item = state.addedItems.find(x=>x.id === action.id). If this item exists, increment, otherwise, add quantity = 1.

How to delete a specific element from an array in the redux store

I am new to to redux and react. Still doing simple tutorials. I managed to create 2 simple components; one that outputs on the screen (as a list) whatever is in the array in the redux store, and the other component contains a button and a textfield which basically adds to that array in the store.
I would like to add a feature that will enable me to delete a specific entry in the list depending on what the user clicked on. I am thinking of creating a <button> next to each <li> tag that gets rendered as it loops through the array, and these buttons will correspond to the respective list elements. But I'm not sure how to do that.
I've tried creating a button when each <li> tag gets created but I was getting an error on the console stating that each element in a list needs a unique ID. I then decided to create another array in my store called buttons which will contain a unique id as well as the id of the list but it got out of hand. I think I might be overcomplicating this. This is what I have at the moment:
Components:
List.jsx (responsible for outputting the list)
import React from 'react'
import { connect } from "react-redux";
const ListComp = ({ lists }) => (
<div>
<ul>
{console.log(lists)}
{lists.map( element => (
<li key={element.id}>
{element.titleToBeAddedToList}
</li>
))}
</ul>
</div>
)
const mapStateToProps = state => {
return {
lists: state.lists
};
}
const List = connect(mapStateToProps)(ListComp)
export default List;
SubmitButton.jsx (responsible for outputting the button and textfield)
import React from 'react'
import { connect } from "react-redux";
import uuidv1 from "uuid";
import { addList } from "../actions/index";
import { addButton } from "../actions/index"
function mapDispatchToProps(dispatch){
return {
addlist: article => dispatch(addList(article)),
addbutton: idOfButton => dispatch(addButton(idOfButton))
};
}
class Submit extends React.Component{
constructor(){
super();
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const {titleToBeAddedToList} = this.state;
const id = uuidv1();
const button_id = uuidv1();
//Dispatching the action:
this.props.addlist({ titleToBeAddedToList, id });
this.props.addbutton({id, button_id});
//Once we've dispatched an action, we want to clear the state:
this.setState({ titleToBeAddedToList: "" });
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="titleToBeAddedToList"
onChange={this.handleChange}
/>
</div>
<button type="submit" className="btn btn-success btn-lg">
SAVE
</button>
</form>
);
}
}
const SubmitButton = connect(null, mapDispatchToProps)(Submit)
export default SubmitButton;
Reducers:
const initialState = {
lists: [],
buttons: []
};
function rootReducer (state = initialState, action) {
if(action.type === "ADD_LIST" ){
return Object.assign({}, state, {
lists: state.lists.concat(action.payload)
});
} else if(action.type === "ADD_BUTTON"){
return Object.assign({}, state, {
buttons: state.lists.concat(action.payload)
});
} else if(action.type === "DELETE_FROM_LIST"){
//.....//
}
return state;
}
export default rootReducer;
Action:
export function addList(payload) {
return { type: "ADD_LIST", payload }
};
export function addButton(payload){
return {type: "ADD_BUTTON", payload }
}
export function deleteList(payload){
return { type: "DELETE_FROM_LIST", payload }
}
Store:
import { createStore } from "redux";
import rootReducer from "../reducers/index";
const store = createStore(rootReducer);
export default store;
You can use Math.random() as an unique key identifier, if the button is click it will call action deleteItem with the ID, action is bound to reducer pass on the ID, you can then use the ID to indentify elements and remove it in the list.
import React from 'react'
import { connect } from "react-redux";
import { deleteItem } from './actions';
const ListComp = ({ lists }) => (
<div>
<ul>
{console.log(lists)}
{lists.map( element => (
<li key={Math.random()} key={element.id}>
{element.titleToBeAddedToList}
<button onClick={() => deleteItem(element.id)}>X</button>
</li>
))}
</ul>
</div>
)
const mapStateToProps = state => {
return {
lists: state.lists
};
}
const List = connect(mapStateToProps, {deleteItem})(ListComp) // Make it available to component as props
export default List;
Action:
export function deleteElement(id) {
return function(dispatch) {
return dispatch({type: "DELETE_FROM_LIST", payload: id})
}
}
Reducer:
case 'DELETE_FROM_LIST': {
const id = action.payload;
return {
...state,
list: state.list.filter(item => item.id !== id)
}
}
else if (action.type === "DELETE_FROM_LIST") {
return Object.assign({}, state, {
buttons: state.lists.filter(item => (item.id !==action.payload))
});
}
you can use filter() for delete.
This is a minimal working react-redux example containing all the pieces to delete an item from an array in redux store.
// reducer.js
const reducer = (state, action) => {
switch (action.type) {
case 'DELETE':
return state.filter(item => (
item.id !== action.payload.id
))
default: return state;
}
}
// Item.js
const Item = ({id, onClick, label}) => (
<li>
{label}
<button onClick={ () => onClick(id) }>
delete
</button>
</li>
)
// ListContainer.js
const mapStateToProps = state => ({ items: state })
const ListContainer = ReactRedux.connect(mapStateToProps)(class extends React.Component {
handleDelete = id => {
const { dispatch } = this.props;
dispatch({ type: 'DELETE', payload: { id } })
}
render() {
const { items } = this.props;
return items.map(({id, label}) => (
<Item
label={label}
id={id}
onClick={this.handleDelete}
/>
))
}
})
// Main.js
const initialState = [
{ id: 1, label: 'item 1' },
{ id: 2, label: 'item 2' },
{ id: 3, label: 'item 3' },
{ id: 4, label: 'item 4' }
]
const store = Redux.createStore(reducer, initialState);
class App extends React.Component {
render(){
return (
<ReactRedux.Provider store={store}>
<ListContainer />
</ReactRedux.Provider>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/6.0.1/react-redux.js"></script>
<div id="root"></div>

PUT Method in action and reducer in Redux

I have created an UPDATE_ITEM type but how to code it in here I don't have the idea since I want to update it by its ID. Also I want to dipatch this action with the reducer itemReducer.js which I have given in the code below. Can someone please help me with the code?//itemAction.js Action. The get, delete and add routes is working but this put method is giving me headache.
import axios from 'axios';
import { GET_ITEMS, ADD_ITEM, DELETE_ITEM, UPDATE_ITEM, ITEMS_LOADING } from'./types';
export const getItems = () => dispatch => {
dispatch(setItemsLoading());
axios.get('/api/items').then(res =>
dispatch({
type: GET_ITEMS,
payload: res.data
})
);
};
export const addItem = item => dispatch => {
axios.post('/api/items', item).then(res =>
dispatch({
payload: res.data
})
);
};
//UPDATE_ITEM Action Here
export const deleteItem = id => dispatch => {
axios.delete(`/api/items/${id}`).then(res =>
dispatch({
type: DELETE_ITEM,
payload: id
})
);
};
export const setItemsLoading = () => {
return {
type: ITEMS_LOADING
};
};
This is the itemReducer which I also need help
import { GET_ITEMS, DELETE_ITEM, UPDATE_ITEM, ADD_ITEM, ITEMS_LOADING
} from '../actions/types';
const initialState = {
items: [],
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case GET_ITEMS:
return {
...state,
items: action.payload,
loading: false
};
case DELETE_ITEM:
return {
...state,
items: state.items.filter(item => item._id !== action.payload)
};
//UPDATE_ITEM Reducer here
case ADD_ITEM:
return {
...state,
items: [action.payload, ...state.items]
};
case ITEMS_LOADING:
return {
...state,
loading: true
};
default:
return state;
}
}
I guess your update looks like the add:
//UPDATE_ITEM Action
export const updateItem = item => dispatch => {
axios.put('/api/items', item).then(res =>
dispatch({
type:'UPDATE_ITEM',
payload: res.data
})
);
};
In your reducer you can use map
case UPDATE_ITEM:
return {
...state,
items: state.items.map(
item =>
item._id === action.payload.id
//return action payload (modified item) instead of
// original item when item id is updated item id
? action.payload
: item//ids not the same, return original item
)
};
import React, { Component } from 'react';
import { Container, ListGroup, ListGroupItem, Button } from 'reactstrap';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { connect } from 'react-redux';
import { getItems, deleteItem, updateItem } from '../actions/itemActions';
import PropTypes from 'prop-types';
class ShoppingList extends Component {
componentDidMount() {
this.props.getItems();
}
onDeleteClick = id => {
this.props.deleteItem(id);
};
render() {
const { items } = this.props.item;
return (
<Container>
<ListGroup>
<TransitionGroup className="shopping-list">
{items.map(({ _id, name, body }) => (
<CSSTransition key={_id} timeout={500} classNames="fade">
<ListGroupItem>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={this.onDeleteClick.bind(this, _id)}
>
DELETE
</Button>
{/*An update button will be called here*/}
{/*<Button
className="update-btn"
color="success"
size="sm"
>
Update
</Button>*/}
<div></div>
<table className="rows">
<thead>
<tr>
<td>Name</td>
<td>Body</td>
</tr>
</thead>
<tbody>
<tr>
<td>{ name }</td>
<td>{ body }</td>
</tr>
</tbody>
</table>
</ListGroupItem>
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
</Container>
);
}
}
ShoppingList.propTypes = {
getItems: PropTypes.func.isRequired,
item: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
item: state.item
});
export default connect(
mapStateToProps,
{ getItems, deleteItem }
)(ShoppingList);

Cannot read property 'push' of undefined React

I am trying to push/redirect to /home after deleting poll. But i get Cannot read property 'push' of undefined
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { vote, deletePoll } from "../store/actions/polls";
import { Pie } from "react-chartjs-2";
class Poll extends Component {
constructor(props) {
super(props);
this.handlePollDelete = this.handlePollDelete.bind(this);
}
handlePollDelete() {
const { deletePoll, id, history } = this.props;
deletePoll(id);
history.push("/home");
}
render() {
const { poll, vote, auth } = this.props;
console.log(auth.user.id);
const userIdPoll = poll.user && poll.user._id;
const userIdAuth = auth.user.id;
const answers =
poll.question &&
poll.options.map(option => (
<button
className="vote-btn"
onClick={() => vote(poll._id, { answer: option.title })}
key={option._id}
>
{option.title}
</button>
));
const data = poll.options && {
labels: poll.options.map(option => option.title),
datasets: [
{
label: poll.question,
backgroundColor: poll.options.map(option => color()),
borderColor: "#323643",
data: poll.options.map(option => option.votes)
}
]
};
return (
<div className="flex-basic-column" style={{ margin: "35px 0 0 0" }}>
<h3>{poll.question}</h3>
{answers}
{userIdAuth === userIdPoll ? (
<button
className="vote-btn delete-btn"
onClick={this.handlePollDelete}
>
delete
</button>
) : null}
{poll.options && <Pie data={data} />}
</div>
);
}
}
export default connect(
state => ({
poll: state.currentPoll,
auth: state.auth
}),
{ vote, deletePoll }
)(Poll);
You want to use the withRouter HOC on your connected component so that the history prop is given to your component.
import { withRouter } from 'react-router-dom';
export default withRouter(connect(
state => ({
poll: state.currentPoll,
auth: state.auth
}),
{ vote, deletePoll }
)(Poll));

Prop returns undefined with redux

Why is my prop returning undefined? I'm trying to access 'total', but its undefined. I pass it in as a prop but it logs to the console as undefined and its also returning blank on the page. I think I might be making a mistake somewhere, because I have done it this way before and it worked.
Here is my container Store.js
import { connect } from 'react-redux';
import { getItems, getCurrency, getTotal} from '../ducks/cart';
import Store from '../components/Store';
const mapStateToProps = (state, props) => {
return {
total: getTotal(state, props)
}
}
export default connect(mapStateToProps)(Store);
Here is my Store.js component:
import React, {Component} from 'react';
import { PropTypes } from 'react';
import Home from '../components/Home';
import Cart from '../containers/Cart';
import ProductList from '../containers/ProductList';
import Checkout from '../containers/Checkout';
const Store = ({ total }) => {
console.error(total);
return(
<div className="container">
<div className="row">
<div className="col-md-12">
<h3>Armor and Weapon Store</h3>
<h4 className="badge badge-warning margin-right">Gold: {total} </h4>
</div>
</div>
<div className="row">
<div className="col-md-8">
<ProductList />
</div>
<div className="col-md-4">
<Cart />
<Checkout />
</div>
</div>
</div>
);
}
Store.propTypes = {
total: PropTypes.number,
}
export default Store;
And here is my redux stuff Cart.js:
import { getProduct } from '../ducks/products';
// actions
const CART_ADD = 'cart/ADD';
const CART_REMOVE = 'cart/REMOVE';
// reducer
const initialState = {
items: [], // array of product ids
currency: 'GOLD'
};
export default function cart(state = initialState, action = {}) {
switch (action.type) {
case CART_ADD:
return handleCartAdd(state, action.payload);
case CART_REMOVE:
return handleCartRemove(state, action.payload);
default:
return state;
}
}
function handleCartAdd(state, payload) {
return {
...state,
items: [ ...state.items, payload.productId ]
};
}
function handleCartRemove(state, payload) {
return {
...state,
items: state.items.filter(id => id !== payload.productId)
};
}
// action creators
export function addToCart(productId) {
return {
type: CART_ADD,
payload: {
productId
}
}
}
export function removeFromCart(productId) {
return {
type: CART_REMOVE,
payload: {
productId
}
}
}
// selectors
export function isInCart(state, props) {
return state.cart.items.indexOf(props.id) !== -1;
}
export function getItems(state, props) {
return state.cart.items.map(id => getProduct(state, { id }));
}
export function getCurrency(state, props) {
return state.cart.currency;
}
export function getTotal(state, props) {
return state.cart.items.reduce((acc, id) => {
const item = getProduct(state, { id });
const total = acc + item.price;
return acc + item.price;
}, 0);
}

Categories