5

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>
    )
}
}
1
  • I think that you should create a component for each card then render a list of those components Commented Dec 4, 2017 at 8:27

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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>

Comments

1

Instead of pass the like in the state you have use your array and update the like of your element depending on the id.

import React, { Component } from 'react';

let 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 = {
       cardArr:cardArr 
    };
     // this.handleClick = this.handleClick.bind(this);


  }



IncrementItem = (id) => {
    let cards = this.state.cardArr;
    cards.find(c => c.id === id).like++;
    this.setState({cardArr:cards});
}
DecreaseItem = (id) => {
    let cards = this.state.cardArr;
    cards.find(c => c.id === id).like--;
    this.setState({cardArr:cards});
}  

render() {

    this.state.cardArr.map((card) => 

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

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

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.