prindod
prindod

Reputation: 21

Counter for each item in React.js

I am trying to implement a counter for each of the elements in an array and display them on the screen. I have an array and I want to display the following for each of the elements: name of the car, likes, increase button, and decrease button. When I tried to increase and decrease the likes, all the elements gets increase and decrease the same way. How do I keep the likes independent from each other and not share the same likes? For example, when I like one car, I want only that one to increase the likes count. Can someone assist me with this problem? This is my current code:

import React, {Component} from 'react';

class Cars extends Component {
  constructor(props) {
    super(props);

    this.state = {
        likes: 0
    };

    this.incFav = this.incFav.bind(this);
    this.decFav = this.decFav.bind(this);
  }

  incFav(e) {
    this.setState({likes: this.state.likes + 1});
  }

  decFav(e) {
    this.setState({likes: this.state.likes - 1});
  }

  render() {
    //Passed this.props.cars from another component. It is an array of cars.
    const { cars } = this.props;
    return (
        <div>
            {cars.map((car, key) => {
                <li key={car}>
                    {car}
                    {this.state.likes}
                    <button onClick={this.incFav}>+</button>
                    <button onClick={this.decFav}>-</button>
                </li>
            })}
        </div>
    );
  }
}

export default Cars;

Upvotes: 2

Views: 3878

Answers (1)

G4bri3l
G4bri3l

Reputation: 5146

Alright, the answer is pretty straightforward. You are confusing the state of your list of cars with the state of each individual car. In this case you have a state for the component Cars, but not for each specific car. My suggestion is to create an additional component called Car, that has its own likes. Your code would look something like this:

import React from 'react';
import Car from '../Car/Car.js';

const Cars = ({ cars }) => (
  <ul>{cars.map((car, key) => <Car car={car} key={car} />}</ul>
);

export default Cars;

As you notice the Cars list does not need to have any info about the state of each single car, that's something you would handle inside each Car component like this:

import React, {Component} from 'react';

class Car extends Component {
  constructor(props) {
    super(props);
    this.state = { likes: 0 };
    this.incFav = this.incFav.bind(this);
    this.decFav = this.decFav.bind(this);
  }

  incFav() {
    this.setState(prevState => ({ likes: prevState.likes + 1 }));
  }

  decFav() {
    this.setState(prevState => ({ likes: prevState.likes - 1 }));
  }

  render() {
    return(
      <li>
        {this.props.car}
        {this.state.likes}
        <button onClick={this.incFav}>+</button>
        <button onClick={this.decFav}>-</button>
      </li>
    );
  }
}

export default Car;

As you may notice there is really not need in this scenario for a Cars component so you can just embed this list in whichever part of your App directly, it's up to you. But having a separate component for each Car will guarantee you that they will have each a separate state with a separate counter for likes. Previously it was shared between all of them, make sure you understand why your code was not behaving as expected.

Upvotes: 2

Related Questions