React function returns undefined

8.6k views Asked by At

I'm about two weeks into studying React and working on my first SPA. I'm loving react and able to figure out many of my problems but I've run into two problems on this MusicPlayer component I'm making.

One is that when I change src in my html audio element the actual audio doesn't change even though the src path does change. I can see it happening in dev tools. I can see the src change when a button is clicked, but the audio that is playing doesn't change. If the audio track finishes it doesn't load the next track. The audio that I hear is always track 1 regardless of what the src is.

My other issue is that songBuilder() is returning undefined. I can't find any bugs in my syntax though they must be there. I used create-react-app as my boilerplate as I don't understand webpack in the slightest yet. Is my map problem a deficit in my JS understanding or is something odd happening with the bundling/build? Please let me know if more information is needed to answer this question. Thank you!

import React, { Component } from "react";

const songRepo = [
  {
    title: "The Silver Swan",
    songLength: "0:13",
    path: require("./songs/thesilverswan.mp3")
  },
  {
    title: "Miracle Cure",
    songLength: "0:12",
    path: require("./songs/miraclecure.mp3")
  },
  {
    title: "Miracle Cure",
    songLength: "0:12",
    path: require("./songs/miraclecure.mp3")
  },
  {
    title: "Miracle Cure",
    songLength: "0:12",
    path: require("./songs/miraclecure.mp3")
  }
];

export default class MusicPlayer extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  songBuilder() {
    return songRepo.map((song, index) => (
      <li
        className={index % 2 === 0 ? "even song_wrapper" : "odd song_wrapper"}
      >
        <span className="song_number"> {index + 1}</span>
        <span key={index + 1} className="song_title">
          {song.title}
        </span>
        <span className="song_length">{song.songLength}</span>
      </li>
    ));
  }

  playerClick(type) {
    if (type === "next_song" && this.state.count < songRepo.length - 1) {
      this.setState({ count: this.state.count + 1 });
    } else if (type === "prev_song" && this.state.count > 0) {
      this.setState({ count: this.state.count - 1 });
    }
  }

  render() {
    return (
      <div className="player">
        <div className="player_nav">
          <div className="player_title">
            <span className="song_number">{this.state.count + 1}</span>
            <span className="song_title">
              {songRepo[this.state.count].title}
            </span>
            <span className="song_length">
              {songRepo[this.state.count].songLength}
            </span>
          </div>
          <audio className="waveform" controls="controls">
            <source src={songRepo[this.state.count].path} type="audio/mp3" />
          </audio>
          <div className="player_buttons">
            <span
              className="prev_song"
              onClick={this.playerClick.bind(this, "prev_song")}
            >
              &lsaquo;&lsaquo;
            </span>
            <span> </span>
            <span
              className="next_song"
              onClick={this.playerClick.bind(this, "next_song")}
            >
              &rsaquo;&rsaquo;
            </span>
          </div>
          <div>
            <ul className="song_list">{songBuilder()}</ul>
          </div>
        </div>
      </div>
    );
  }
}
1

There are 1 answers

6
Vikram Saini On BEST ANSWER

try to call this method as

<ul className="song_list">{this.songBuilder}</ul>

initially you called your method as

songBuilder()--returns "undefined" since this points to the window

this.songBuilder--works as this point to current object

If your function is defined within an object, calling it directly from an object will set its context to the object on which the function is being called.