Home > Blockchain >  How do I get my context value into my state value?
How do I get my context value into my state value?

Time:10-26

I've created a music player and I'm trying to add a function that adds a song to the audio player component when the song image is clicked.

I've used the createContext hook to access my state value globally as it makes it easier to pass my values.

As seen in the code below, I have an onClick function in the SongGrid component that gets the song file and stores it in the songClicked state. This state value is then accessed in my MusicPlayer component through the createContext hook.

When I view the createContext hook in the console, It shows that the songClicked value has updated to the songFile that I was referencing.

After doing this, I then set the currentSong value (which updates audio player source file) to my songClicked state which should then play the song file.

Does anyone know why the song will still not play? Is there something I'm missing? I'll simplify the source code to make it more readable.

// Context.js file which is imported into files.

import { createContext } from "react";

export const songContext = createContext({});


// Music.js file with songs that are passed as a prop into the SongGrid component.

import DrakeOneDance from '../music/Drake_One_Dance.mp3'
import AdelleHello from '../music/Adele_Hello.mp3'
import JuiceWrldLucidDreams from '../music/Lucid_Dreams.mp3'
import KingsOfLeonPyro from '../music/Pyro.mp3'

<div className='music-container'>
            <SongGrid songs={songs} />
        </div>

import React, { useState } from 'react';
import { useContext } from 'react';
import {songContext} from '../pages/Context'

function SongGrid({songs}) {

  const { songClicked, setSongClicked } = useContext(songContext)
  
   function getSongOne() {
    let songFile = songs.map(song => song.songFile)
    setSongClicked(songFile[0]) // Grabs the first song file in the songs array
   }

  return (

    <div className="song-main-container">
            <img src={Rap} onClick={getSongOne} />
    </div>

  )
}

export default SongGrid

import React, { useState, useEffect, useRef } from 'react'
import {songContext} from '../pages/Context'
import { useContext } from 'react';



function MusicPlayer({songs}) {

    // References audio player tag to update source file.
    const audioPlayer = useRef()

    //State
    const { songClicked, setSongClicked } = useContext(songContext)
    const [currentSong] = useState(songClicked); // This should update audio src file?
    const [isPlaying, setisPlaying] = useState(false);


    function togglePlay() {
        if(!isPlaying) {
            audioPlayer.current.play()
        } else {
            audioPlayer.current.pause()
        }
        setisPlaying(isPlaying => !isPlaying)
    }

    
  return (


    <div className='music-player-container'>

      <audio src={currentSong} ref={audioPlayer} muted={mute} /> 
      
    </div>


  )
}

export default MusicPlayer

CodePudding user response:

The currentSong state in your MusicPlayer component is not being updated when songClicked changes.

You correctly set the initial state of currentSong using const [currentSong] = useState(songClicked); however subsequent changes will not be set.

To do this, you have to make use of useEffect in your MusicPlayer component, like so:

function MusicPlayer({songs}) {

    ...

    const { songClicked, setSongClicked } = useContext(songContext)
    const [currentSong, setCurrentSong] = useState(songClicked); // This should update audio src file?

    ...

    useEffect(() => {
       setCurrentSong(songClicked)
       
       if (songClicked) {
           audioPlayer.current.play()
       }
    }, [songClicked])


  return (
    <div className='music-player-container'>
      <audio src={currentSong} ref={audioPlayer} muted={mute} /> 
    </div>
  )
}

export default MusicPlayer

I would however question why you need to hold your state in both the SongContext and the MusicPlayer. If songClicked is always going to be the same as currentSong, then I would remove currentSong altogether and just supply songClicked to your audio element.

...

<audio src={songClicked} ref={audioPlayer} muted={mute} /> 

...
  • Related