3

I'm making Add to favorite function in React. Thanks to everyone's help I could somehow make that work except for toggling like and dislike. I coded like "likes: this.state.likes.filter(e => e.name !== person.name)" just because someone advised me to code so. To be honest I don't understand the code above maybe because it's ES6 syntax. How does it look like in ES5? And right now that code is not working, elements are not added to the array properly. How do I fix this code?

import React from 'react';
import axios from 'axios';
import IcoMoon from 'react-icomoon';

export default class PersonList extends React.Component {

    state = {
        persons: [],
        likes: []
    }

    componentDidMount() {
        axios.get(`https://jsonplaceholder.typicode.com/users`)
            .then(res => {
                const persons = res.data;
                this.setState({ persons });
            })
    }

    handleClick = person => {

        if (this.state.likes.filter(e => e.name === person.name).length > 0) {

            this.setState({
                likes: this.state.likes.filter(e => e.name !== person.name)
            });

            console.log(this.state.likes);
            return;
        }

        this.setState({
            likes: [...this.state.likes, person]
        });       
    };

    likesTemplate = item => <li key={item}>{item}</li>;

    renderLikes = () => {
        return this.state.likes.map(i => this.likesTemplate(i));
    }

    render() {
        return (
            <div>
                {this.state.persons.map(person => {
                return <li key={person.name}><IcoMoon icon="heart" onClick={() => {this.handleClick(person.name)}} />{person.name}</li>}
            )}

            <h2>Favorite Person</h2>
            <ul>
                {this.renderLikes()}
            </ul>
            </div>
        )
    }
}
6
  • 1
    Have you tried with Array​.prototype​.includes() to check if an element exists in an array. See here: developer.mozilla.org/it/docs/Web/JavaScript/Reference/… Commented Jun 6, 2019 at 8:26
  • 1
    Using Set instead of array could be a good idea, too. Avoiding duplicates is the nature of a set afterall. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Jun 6, 2019 at 8:44
  • I tried it and it works! "if (this.state.likes.includes(person)) {". Now my problem is I can't figure out how to remove duplicated element in the array. I'm trying like "this.setState({ likes: this.state.likes.splice(person) });" but it won't work :( Commented Jun 6, 2019 at 8:45
  • 1
    try this.state.likes.splice(this.state.likes.indexOf(person), 1) Commented Jun 6, 2019 at 8:46
  • Tried the code above but it seems like I messed up everything. If I click for the first time the array is still empty, and if I click another person then previous person is added to the array. Commented Jun 6, 2019 at 8:59

2 Answers 2

6

The right condition is

if (!(this.state.likes.filter(e => e.name === person.name).length > 0)) {
  // your code
}

The meaning of the condition is:

this.state.likes.filter(e => e.name === person.name).length > 0) This will filter out the array only when an element of the array matches with the provided person object name. It points out that the person is already present in the array

The ! is used to check the opposite condition, because you want enter in your if statement only if person does not exists

EDIT Reading better your code, this could be accomplished with a simpler, cleaner method:

  addPerson = (person) => {
    let filteredPerson = this.state.likes.filter(like => like.name !== person.name);
    this.setState({
      likes: [...filteredPerson, person]
    })        
  }

Check out this working snippet: https://stackblitz.com/edit/react-jxebwg

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

3 Comments

Fixed, a parenthesis issue. You cal also check alternatively that length should be < 1, without !
So if the array does not include person, then splice? Maybe it's opposite?
If I click a person and click again it sure toggles, but if I another person before I toggle, the likes array turns empty. Btw thank you for the link. That service looks useful.
0

You can approach this in a couple of different ways.

Edit: Now that we know likes is just an array of strings

Using .includes()

handleClick = person => {
    const likes = this.state.likes
    //check to see if person has already liked 
    if (likes.includes(person)) {
       //user has already liked. Choose one option (1 or 2)
       
       //Option 1: create a new like array without the current user
       const newLikes = likes.filter((like) => like !== person)
   
       //Option 1: update state with new likes
       this.setState({
          likes: newLikes
       })

       //Option 2: or do nothing
       return;

    //this executes if the user has not liked yet
    } else {
      this.setState({
        likes: [...likes, person]
      })
    }    
};

So what I mean by "do one of the following" is dependent on how you want your feature to behave.

Option 1: If you want to create a sort of toggle-effect, where the user has already liked the item. You should select option one where we create a new arr and update state. This will "unlike", removing the user from the liked array. And then clicking

Option 2: would be just to do nothing. if the user clicks the button and they have already liked it, this would just keep the status the same.

6 Comments

Thank you for your detailed explanation. I didn't know .filter removes specific element. However the code is not working as I intended. The toggle happens even when I click other icons.
@kayak I'm not sure what you mean by other icons? Do you mean the icon that belongs to a different like changes when you click on an icon?
Sorry for the confusion. Maybe I should do "if (likes.map(like => like).includes(person))" ? I removed all the ".name" and it finally worked!
Not sure if "if (likes.map(like => like).includes(person))" syntax is correct though..
@kayak ahh okay I see what went wrong here. You're already passing person.name into your handleClick function when you render these icons. Also it looks like the likes array is just an array of strings which are just the person names. I thought it would be an object. In this case, we only need .includes(). Let me update my answer to clean up the solution.
|

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.