0
votes

I'm new to React/Redux.

I'm making simple shopping cart. Right now I'm trying to display data from local json file. The data is in state like: {items: data here }. I can map over this items when I write reducer on the top level reducer file. However if I use combineReducers it will give me error saying "this.props.items is undefined: return this.props.items.slice(0, 20).map(item => ".

How do I access and map over the items?

Reducer #1 cartReducer.js

import data from "../data.json";

const INITIAL_STATE = {
    items: data,
    addedItem: [],
    total: 0
}

const cartReducer = (state = INITIAL_STATE, action) => {
    return state;
}

export default cartReducer;

Reducer #2

import { combineReducers } from 'redux';
import items from './cartReducer';

export default combineReducers({
    items
})

Component to display items list

import React from 'react';
import { connect } from 'react-redux';
import { addToCart } from '../actions';

class ItemList extends React.Component {

    renderList() {
      return this.props.items.slice(0, 20).map(item => {
        return (
          <div className="card" key={item.id}>
                <span className="card-title">{item.name}</span>                
                <p>{item.content}</p>
                <p><b>Price: {item.price}$</b></p>    
          </div>
        )
      })      
    }

    render() {
        return (
          <div>
             {this.renderList()}
           </div>
        )
    }
}

const mapStateToProps = state => {
  return {
    items: state.items
  }
}

const mapDispatchToProps = dispatch => {
  return {
    addToCart: (id) => {
      dispatch(addToCart(id))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(ItemList);

JSON data

[
  {
      "id": 201,
      "name": "Nulla",
      "price": 207,
      "subCategoryId": 101,
      "categoryId": 1,
      "rate": 2.44,
      "content": "Culpa sed tenetur incidunt quia veniam sed mollitia exercitationem. Laboriosam reprehenderit laborum pariatur ea rem qui inventore. In asperiores dignissimos temporibus et. Beatae consequatur corrupti nam praesentium.",
      "review": 78,
      "typeVariant": "D",
      "colorVariant": "5",
      "imageUrl": "https://placeholdit.imgix.net/~text?txtsize=55&txt=137x945&w=137&h=945"
    },{
      "id": 202,
      "name": "Corporis",
      "price": 271,
      "subCategoryId": 101,
      "categoryId": 1,
      "rate": 2.18,
      "content": "Nam incidunt blanditiis odio inventore. Nobis voluptatum quibusdam laboriosam a numquam. Delectus sequi ipsa possimus ratione repellendus quibusdam. Molestiae fuga laudantium natus dolorem.",
      "review": 67,
      "typeVariant": "A",
      "colorVariant": "4",
      "imageUrl": "https://dummyimage.com/931x785"
    }
]
3
Try debugger or console.log(this.props) as the first line in the render method. Seems that that your component has not received the expected props. - HÃ¥ken Lid
When I did console.log(this.props) it gave me an object containing each state, which was not able to map over. In order to use map, state seems to have to look like return { items: state.items.items }. That will give me an array. - kayak

3 Answers

2
votes

When you create a reducer using combineReducers you create a reducer that will call each reducer passed to it, gathering their result into a new state object. The key for each reducers state will be the key that you gave the respective reducer in the object you passed to combineReducers.

If you use only your reducer, your resulting state would be as you expected:

{
    items: Array
    addedItem: Array
    total: number
}
export default combineReducers({
    items
})

Is syntactic sugar for

export default combineReducers({
    items: items
})

Which means that the final state will look something like this:

{
    items: {
        items: Array
        addedItem: Array
        total: number
    }
}

As such, you can access the items array in your state using state.items.items

1
votes

You don't bind renderList and that's why props is undefined. "This" refers to the calling function (renderList) and not your component. And the function does not have a field props because it is just a function. You have to bind it within the constructor like this: this.renderList= this.renderList.bind(this); or use a array function like this: const renderList = () => {...}. Now "this" refers to the component and props will be defined.

-1
votes

you have to pass type in dispatch

const mapDispatchToProps = dispatch => {
  return {
    addToCart: id => {
      dispatch({ type: 'name of your type' });
    }
  };
};

and then add condition to your reducer

const cartReducer = (state = INITIAL_STATE, action) => {
   if(action.type === 'name of your type')
      return state;
}