简体   繁体   中英

this.props Not Returning Fetched Data From Parent Component (React)

I am attempting to render playlist information for an Audio Player in React. The data is coming from a fetch call in the parent component (PostContent.js). The data being returned is an array of objects that looks like: [ {name: 'track name', artist: 'artist name', url: ' https://blahblah.wav ', lrc: 'string', theme: 'another string' }, {…}, {…}, etc. }

I am not able to return the data in the render() method of the child component (AudioPlayer.js). When I console.log(this.props.audio) in the render(), my terminal prints three responses. The first is an empty array, and the next two are the correct data that I need (an array of objects).

How can I set the props on the 'audio' key in the 'props' object in the render() method of the AudioPlayer.js component?

I should mention that I am using the react-aplayer library, and I am able to make this work with hard-coded data, as in the example here ( https://github.com/MoePlayer/react-aplayer ), but I am trying to make a dynamic playlist component for a blog website. Any advice is greatly appreciated.

AudioPlayer.js (Child Component)

import React, { PureComponent, Fragment } from 'react';
import ReactAplayer from '../react-aplayer';
import './AudioPlayer.css';
import sample from '../../src/adrian_trinkhaus.jpeg';


export default class AudioPlayer extends React.Component {
  // event binding example
  onPlay = () => {
    console.log('on play');
  };

  onPause = () => {
    console.log('on pause');
  };

  // example of access aplayer instance
  onInit = ap => {
    this.ap = ap;
  };

  render() {
    console.log('props in render of AudioPlayer', this.props.audio)
    const props = {
      theme: '#F57F17',
      lrcType: 3,
      audio: this.props.audio
    };

    return (
      <div>
        <ReactAplayer
          {...props}
          onInit={this.onInit}
          onPlay={this.onPlay}
          onPause={this.onPause}
        />
      </div>
    );
  }
}

PostContent.js (Parent Component)

import React, { Component, useState, Fragment } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import AudioPlayer from './AudioPlayer';

export default class PostContent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      id: '',
      episodeData: [],
      audio: []
    }
  }

  async componentDidMount() {
    const { id } = this.props.match.params;
    const response = await fetch(`http://localhost:5000/episode/${id}/playlist`);
    const jsonData = await response.json();
    const songs = jsonData;
    const audio = Object.keys(songs).map(key => {
      return {
        name: songs[key].name,
        artist: songs[key].artist,
        url: songs[key].url,
        cover: songs[key].cover,
        lrc: songs[key].lrc,
        theme: songs[key].theme
      }
    });
    this.setState({ audio })
  }


  componentDidUpdate(prevProps, prevState) {
    if (prevState.audio !== this.state.audio) {
      const newAudio = this.state.audio;
      this.setState({ audio: newAudio }, () => console.log('new audio', this.state.audio))
    }
  }

  render() {
    return (
      <Fragment>
        <AudioPlayer audio={this.state.audio} />
        <Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
        {this.state.episodeData.map((item, i) => (
          <div key={i} className="word-content">
            <h2 className="show-title">{item.post_title}</h2>
            <div className="episode-post-content">
              <p>{item.post_content1}</p>
              <p>{item.post_content2}</p>
              <p>{item.post_content3}</p></div>
          </div>
        ))}
        <Table data={this.state.data} />
        <div className="bottom-link">
          <Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
        </div>
      </Fragment>
    )
  }
}

Actually I think it doesnt work because you set this.props inside a props obejct, so maybe you need to do something like

var that = this 
const props = {
  audio = that.props.audio 
}

i played around with an async scenario with your code on codesandbox

i think the problem is when you're trying to access the payload in ReactAPlayer component when audio it's not loaded yet from the async call. what you need to do is only use "audio" when it's valid like this if (audio.length) {...} or audio &&... some form of check to prevent it from being accessed in the reactAplayer render function.

fyi - you can remove the componentDidUpdate hook, since you have a setState call inside the...Didmount hook, when setState is called inside...didMount, the component calls its render() thus trigger a child re-render and its child will do the same..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM