DjBillje Official
DjBillje Official

Reputation: 386

Warning: Each child in a list should have a unique "key" prop even tho it has unique key React

so i wanted to render array but it keeps on saying , Warning: Each child in a list should have a unique "key" prop even tho it has unique key, my array contains three elements and it does not even render the third array properly, the button doesnt even work of third li for some reason.

import React, { useEffect, useRef } from "react";
import fire from "./firebase";
import firebase from "firebase"
import { useState } from "react"
import Header from "./header"
import Nav from "./nav"
import { NavLink, Redirect } from "react-router-dom";
import AudioPlayer from "./audioplayer"   

const Music = ({ match }) => {
    const audioRef = useRef();
    const audioPlayer = audioRef.current
    const [audioSrc, setAudioSrc] = useState()
    const [musics, setMusics] = useState([])
    const [user, setUser] = useState(null)
    const [pfp, setPfp] = useState(null)
    const [audioTitle, setAudioTitle] = useState(null)
    const { params: { uID } } = match;
    var userName;
    var tracksTitle = [];
    useEffect(()=>{
        firebase.database().ref("users/"+uID+"/praivate/login credentials").on("value", (snapshot)=>{
            setUser(snapshot.val().userName)
            setUser(snapshot.val().userName)
        })
        firebase.database().ref("users/"+uID+"/public/profile/pic").on("value", (snapshot)=>{
            console.log(snapshot.val().pfpUrl)
            setPfp(snapshot.val().pfpUrl)
        })
    }, [])
    var music;

    //maybe the problem is over here somewhere
    useEffect(()=>{
        firebase.database().ref("users/"+uID+"/public/songs/").on("value", (snapshot)=>{
            //stores data in music.
            music = snapshot.val()
            //gets all title of the data
            Object.values(music).forEach((value)=>{  
                tracksTitle.push(value.title)//pushes titles to tracksTitle
            })
            setMusics(tracksTitle) //stores all track title in musics
        })
       
    }, [uID])

    const [progVal, setProgVal] = useState("0%")
    function update(event){
        let duration = (event.target.currentTime/event.target.duration)*100
        setProgVal(duration)
    }
    
    function play(event){
        const value = event.target.getAttribute("value")
        console.log(value)
        if(value){
            firebase.database().ref("public/songs/"+value).on("value", (snapshot)=>{
                setAudioSrc(snapshot.val().aduioURL)
            })
        }
        setAudioTitle(value)
        audioPlayer.play()
        
    }

    function playAudio(){
        audioPlayer.play()
    }

    

    function stop(event){
        audioPlayer.pause()
    }

   
    
    return(
        <>
            <Nav />
            <div id = "profile" className = "main">
                <audio id = "player" ref = {audioRef} src = {audioSrc} name = "audioplayer" onTimeUpdate = {update}>
                </audio>
                <div class = "profile-container">
                    <div className = "cover-pic">
                        <img src = "" />
                        <div className = "pfp">
                            <img src = {pfp} height = "100" width = "100"/>
                        </div>
                        <div className = "User-Name">
                            <h1>{user}</h1>
                        </div>
                    </div>
                    <div class = "tabsContainer">
                    <div class = "tabs-holder">
                    <NavLink to = {"/u/"+uID+"/music"}><button><span>Music</span></button></NavLink>
                        <button><span>Playlist</span></button>
                        <button><span>About</span></button>
                    </div>
                </div>
                </div>
               
                <div class = "music-content-container">
                    <div class = "music-box">
                        <div class = "user-musics">
                            <ul>
                                {musics && musics.map((name, i)=>{
                                    console.log()
                                    return(
                                        <>
                                            //it does not render the third array properly
                                            <li key = {i}><button onClick = {play} value = {name}>Play</button>{name}</li>
                                        </>
                                    )
                                })}
                            </ul>
                        </div>
                    </div>
                </div>
                
            </div>
            <AudioPlayer progVal = {progVal} stop = {stop} playAudio = {playAudio}/>
            <Header />
        </>
    )
    }  
export default Music
//
Can you guys please help me to figure out the problem, thank you in advance.

update: my data from firebase looks like this:

enter image description here

and this code will select title of each data

useEffect(()=>{
        firebase.database().ref("users/"+uID+"/public/songs/").on("value", (snapshot)=>{
            //stores data in music.
            music = snapshot.val()
            console.log(music)
            //gets all title of the data
            Object.values(music).forEach((value)=>{ 
                 
                tracksTitle.push(value.title)//pushes titles to tracksTitle
            })
            setMusics(tracksTitle) //stores all track in musics
        })

enter image description here

the button of "fikka fikka" doesnt even work when i hover over the "fikka fikka" it doesnt even change the cursor to text curosr while in ed sheeran and one direction it doesnt have that problem

Upvotes: 10

Views: 1987

Answers (1)

Drew Reese
Drew Reese

Reputation: 202667

React keys need to be on the outer-most returned element from the mapping.

{musics && musics.map((name, i)=>{
  return(
  <Fragment key={i}>
    //it does not render the third array properly
    <li>
      <button onClick={play} value={name}>Play</button>
      {name}
    </li>
  </Fragment>)
})}

Notice here that in order to do this the react fragment shorthand is incompatible, you must use the Fragment component. Or since there is only a single element the Fragment is mostly useless, remove it and place the key on the li where it was.

{musics && musics.map((name, i)=>{
  return(
  <li key={i}>
    <button onClick={play} value={name}>Play</button>
    {name}
  </li>)
})}

Upvotes: 8

Related Questions