Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mapping an array of objects and changing the value with on onClick in React

I'm trying to change the value of like within the cardArr objects while using a map() to list each obj.

Below is my code. Current, it works, but every object shares the same counter since it's not calling from the object. I understand that I'm currently just calling the object property stored in state, but how do I edit the like in each object using a map function?

import React, { Component } from 'react';

const cardArr = [
{
    id: 1,
    text: "Hey this is a test.",
    img: " ",
    like: 0
},
{
    id: 2,
    text: "If this works I'll call it a day.",
    img: " ",
    like: 0
},
{
    id: 3,
    text: "I'll drink a lot of beer.",
    img: " ",
    like: 0
},
{
    id: 4,
    text: "Cheers",
    img: " ",
    like: 0

}
]


export class Card extends Component {
    constructor(props) {
    super(props);
    this.state = {
      like: 0,
      show: true
    };
     // this.handleClick = this.handleClick.bind(this);


  }



IncrementItem = () => {
    this.setState({ like: this.state.like + 1 });
}
DecreaseItem = () => {
    this.setState({ like: this.state.like - 1 });
}

// handleClick(e) {
//  e.preventDefault();
//  this.IncrementItem();
// }
// handleClick(e) {
//  e.preventDefault();
//  this.DecreaseItem();
// }


render() {

    const cardList = (cardArr.map((card) => 

        <ul>
            <li>
            <div key={card.id}>
                {card.text};
                <img src={card.img}/>
                <p>Like Button</p>
                <button onClick={this.handleClickAdd}>Like</button>
                <p>Dilike Button</p>
                <button onClick={this.DecreaseItem}>Disike</button>
                <p>Likes: {this.state.like}</p>
            </div>
            </li>
        </ul>
        ));

    return(
        <div id='card'>
            {cardList}
        </div>
    )
}
}
like image 883
Nicholas Hrboka Avatar asked Dec 04 '17 08:12

Nicholas Hrboka


People also ask

How do I change the value of an array in a React?

To update an object in an array in React state: Use the map() method to iterate over the array. On each iteration, check if a certain condition is met. Update the object that satisfies the condition and return all other objects as is.

How do I change the value of an object in react JS?

State can hold any kind of JavaScript value, including objects. But you shouldn't change objects that you hold in the React state directly. Instead, when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy.

Can I use onClick on Div React?

To set your mind at ease, the onClick event does work with divs in react, so double-check your code syntax.


2 Answers

Move cardArr to your component's state so on each onClick (like or deslike) you will be able to change like prop as you want:

const Card = ({ card, onLike, onDeslike }) =>
  <div>
    {card.text}
    <p>Likes: {card.like}</p>
    <button onClick={() => onLike(card.id)}>Like</button>
    <button onClick={() => onDeslike(card.id)}>Deslike</button>
  </div>

class CardList extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      cards: [
        {
          id: 1,
          text: 'Hey this is a test.',
          img: ' ',
          like: 0,
        },
        {
          id: 2,
          text: "If this works I'll call it a day.",
          img: ' ',
          like: 0,
        },
        {
          id: 3,
          text: "I'll drink a lot of beer.",
          img: ' ',
          like: 0,
        },
        {
          id: 4,
          text: 'Cheers',
          img: ' ',
          like: 0,
        },
      ]
    }

    this.handleLike = this.handleLike.bind(this)
    this.handleDeslike = this.handleDeslike.bind(this)
  }

  handleLike(id) {
    this.setState(prevState => ({
      ...prevState,
      cards: prevState.cards.map(card => ({
        ...card,
        like: card.id === id ? card.like + 1 : card.like
      }))
    }))
  }

  handleDeslike(id) {
    this.setState(prevState => ({
      ...prevState,
      cards: prevState.cards.map(card => ({
        ...card,
        like: card.id === id ? card.like - 1 : card.like
     }))
    }))
  }

  render() {
    return (
      <div>
        <ul>
          {this.state.cards.map(card =>
            <li key={card.id}>
              <Card
                card={card}
                onLike={this.handleLike}
                onDeslike={this.handleDeslike}
              />
            </li>
          )}
        </ul>
      </div>
    )
  }
}

ReactDOM.render(
  <CardList />,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Don't forget that setState is asynchronous and, therefore, you won't have it's latest changes right away.

like image 151
mersocarlin Avatar answered Nov 01 '22 23:11

mersocarlin


What about to make separation. Create an additional component for cardAddr. And move the render and like working logic to CardAddr component.

const cardArr = [
{
    id: 1,
    text: "Hey this is a test.",
    img: " ",
    like: 0
},
{
    id: 2,
    text: "If this works I'll call it a day.",
    img: " ",
    like: 0
},
{
    id: 3,
    text: "I'll drink a lot of beer.",
    img: " ",
    like: 0
},
{
    id: 4,
    text: "Cheers",
    img: " ",
    like: 0

}]

class CardAddr extends React.Component {
    constructor(props) {
    super(props);
    this.state = this.state = props.card;
  }
   
  IncrementItem = () => {
    this.setState({ like: this.state.like + 1 });
  }
  DecreaseItem = () => {
    this.setState({ like: this.state.like - 1 });
  }
  
  render() {
  	return (
        <div key={this.state.id}>
            {this.state.text}
            <img src={this.state.img}/>
            <p>Like Button</p>
            <button onClick={this.IncrementItem}>Like</button>
            <p>Dilike Button</p>
            <button onClick={this.DecreaseItem}>Disike</button>
            <p>Likes: {this.state.like}</p>
        </div>
    )
  }
}

class Card extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      show: true
    };
  }

render() {
    const cardList = (cardArr.map((card) => 
        <ul key={card.id}>
            <li>
              <CardAddr card={card}/>
            </li>
        </ul>
    ));

    return(
        <div id='card'>
            {cardList}
        </div>
    )
}
}

ReactDOM.render(
  <Card />,
  document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
    
</div>
like image 40
Mikhail Katrin Avatar answered Nov 02 '22 01:11

Mikhail Katrin