0

I want to use either forEach or map to loop through an array that has multiple objects in it. These objects have a key price and a value for it. I'm was trying to use forEach but I can't get it to work. This is my component:

import React, { Component } from 'react';
import {addCart} from './Shop'; 
import { connect } from 'react-redux';

export class Cart extends Component {
    constructor(props) {
        super(props);
        this.state = {items: this.props.cart,cart: [],total: 0};
    }

    ...

    countTotal() {
        this.state.cart.forEach((item, index) => {
            console.log(this.state.items);
            this.state.total = this.state.total + this.state.items.price;
            console.log(this.state.total);
        })
    }

    ...

    render() {
        return(
            <div className= "Webcart" id="Webcart">
            </div>
        );
    }
}

...

In countTotal, console.log(this.state.items) outputs various objects that each look like

item:"Hoodie"
price:25
size:"large"

How can I loop through each object and get the price value so I can add it up in my function?

1

2 Answers 2

3

You should not assign directly to state, you should use setState instead. forEach is fine, but I would recommend you skip forEach and map and use reduce, pulling only the price key out of the object:

countTotal() {
   this.setState({
      total: this.state.cart.reduce((total, { price }) => total + price, 0)
   });
}
Sign up to request clarification or add additional context in comments.

13 Comments

If I do console.log(this.state.total) after this.setState() { I get 0..
setState is asynchronous, your console log will fire before it is done. Put the console log in the render method or render the total
I would suggest using the callback form of setState as you are accessing this.state to calculate the new state: this.setState(prevState => ({ total: prevState.cart.reduce((total, {price}) => total + price)});
Even placing it in my render emthod gives me 0 @RobM.
@RobM. Its not official. React 16 doesn't have async rendering on. When it does, object form of setState can lead to issues. You can checkout Lin Clark's talk about Fiber where she mentions it. youtube.com/watch?v=ZCuYPiUIONs. (Travelling right now. Will post the exact seconds of the video later)
|
0

To answer how to loop through an array, you can use a simple for loop in javascript as you would in a language like C;

let total = 0;
for(let i = 0; i < items.length; i++) {
    total += item[i].price
}

React following a functional approach, we prefer map and reduce as it makes your code more declarative. Hence,

const total = items.reduce((acc, item) => {
  return acc + item.price;
}, 0)

Your code would look like this then,

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';


export class Cart extends Component {
  constructor(props) {
    super(props);
    this.state = {items: props.cart,cart: [],total: 0};
  }


  countTotal() {
    return this.state.items.reduce((acc, item) => {
      return acc + item.price;
    }, 0)
  }

  render() {
    return(
      <div className= "Webcart" id="Webcart">
        { this.countTotal() }
      </div>
    );
  }
}

class App extends Component {
  render() {
    return (
      <Cart cart={
              [
                {
                  item:"Hoodie",
                  price:25,
                  size:"large"
                },
                {
                  item:"Gloves",
                  price: 12,
                  size:"large"
                },
                {
                  item:"boots",
                  price:30,
                  size:"large"
                },
              ]
            } />
    );
  }
}

export default App;

Note There is not setState used. total is derived data. Derived data must not reside in state.

Yet if for some reason you still need it, countTotal would look like this,

countTotal() {
   this.setState(state => {
     return {
        total: state.items.reduce((acc, item) => {
          return acc + item.price;
        }, 0)
     };
   });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.