0

I'm having some difficulty with grabbing specific data from list items that are coming from an API that is being mapped using React.

Here in my render I'm mapping over a list of artists and based on that it'll render the artists name, song title and the URL of the sheet music:

render(){
    return(
        <div className="songContainerOuter">
            {this.props.artist.map((artist, i) => {
                return (
                    <div className="songContainerInner" key={i}>
                        <ul>
                            <div className="leftSide">
                                <li ref={ref => this.artistName = ref}>{artist}</li>
                            </div>
                            <div className="rightSide">
                                <div className="topRight">
                                    <li ref={ref => this.songTitle = ref}>{this.props.title[i]}</li>
                                </div>
                                <div className="bottomRight">
                                    <li ref={ref => this.songUrl = ref}><a href={`${this.props.link[i]}`}><i className="fas fa-link"></i></a></li>
                                    <li onClick={this.addFavourite}><i className="fas fa-plus"></i></li>
                                </div>
                            </div>
                        </ul>
                    </div>
                )
            })}
        </div>
    )
}

Then on click of an li which is a plus icon, I want to store the values in each individually rendered div. The problem I'm having is that when I click on the add button, in my console log I'm getting all of the data back and the exact same song, artist and URL regardless of which mapped div add button I'm clicking on:

addFavourite(e){
    e.preventDefault();
    const favs ={
        artist: this.artistName.textContent,
        title: this.songTitle.textContent,
        url: this.songUrl.textContent.outerHTML,
    };
    const newFavs = Array.from(this.state.favourites);
    newFavs.push(favs);
    this.setState({
        favourites: newFavs
    })
    console.log(this.state.favourites)
}

Is there an alternative way to store the values within the li tags and store ONLY the values uniquely within each mapped div?

1

3 Answers 3

1

Please try the following. If you want to check if your state is updated properly, please refer to @Ved answer.

addFavourite(artist, songIndex){
    const fav = {
        artist,
        title: this.props.title[songIndex],
        url: this.props.link[songIndex]
    };

    const newFavs = Array.from(this.state.favourites);
    newFavs.push(favs);

    this.setState({
        favourites: newFavs
    });
}

render(){
    return (
        <div className="songContainerOuter">
            {this.props.artist.map((artist, i) => {

                const { link, title } = this.props;

                return (
                    <div className="songContainerInner" key={i}>
                        <ul>
                            <div className="leftSide">
                                <li>{artist}</li>
                            </div>
                            <div className="rightSide">
                                <div className="topRight">
                                    <li>{title[i]}</li>
                                </div>
                                <div className="bottomRight">
                                    <li><a href={`${link[i]}`}><i className="fas fa-link"></i></a></li>
                                    <li onClick={event => this.addFavourite(artist, i)}><i className="fas fa-plus"></i></li>
                                </div>
                            </div>
                        </ul>
                    </div>
                )
            })}
        </div>
    )
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this! It works! I had a different solution in place over night where on click i just did document.getElementById, but I'm not sure if that's just not as elegant as your solution is. I'll take a look at this more in depth to understand it.
0

The problem is you are trying to get data just after setState. setState is async operation hence you are getting old data. try putting logs inside setState callback.

    addFavourite(e){
        e.preventDefault();
        const favs ={
            artist: this.artistName.textContent,
            title: this.songTitle.textContent,
            url: this.songUrl.textContent.outerHTML,
        };
        const newFavs = Array.from(this.state.favourites);
        newFavs.push(favs);
        this.setState({
            favourites: newFavs
        },()=>{
       console.log(this.state.favourites)//inside setState callback
})
       }

Comments

0

@anbhd, can you please make the following changes and test it: Add the following section to the constructor section:

 constructor(props) {
    super(props);
    this.addFavourite = this.addFavourite.bind(this);
}
  addFavourite(artist) {
    console.log(artist)
  }

And change the onClick function like the following:

<li onClick={this.addFavourite(artist)}><i className="fas fa-plus"></i></li>

2 Comments

Apologies, I have the constructor set up that way. If I change the li onClick to what you proposed, I don't get any data back so that doesn't work.
Can you please change it to onClick={this.addFavourite(artist)} and change your function to ``` addFavourite(artist) {console.log(artist)}```

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.