使用componentDidUpdate()和React-APlayer库更新状态

时间:2020-04-22 17:20:25

标签: javascript reactjs

我正在尝试使用从父组件中的提取请求接收的数据更新状态。我正在使用“反应播放器”库(https://github.com/MoePlayer/react-aplayer)作为音频播放器。

我能够将歌曲硬编码到播放列表中,如下面的“ this.state.audio”所示。但是,当尝试将此数据更改为通过componentDidUpdate()方法通过道具接收的数据时,我无法将setState设置为新数据。当我在console.log“ this.state.audio”中查看数据时,我收到两条消息:第一条消息带有硬编码的播放列表信息,第二条消息包含从提取请求中接收到的数据。

如何使用新数据更新状态,以代替硬编码数据?

这是我的组成部分:

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

export default class AudioPlayer extends React.Component {
  constructor(props){
    super(props);
    this.state =  {
      theme: '#F57F17', //#F57F17,
      lrcType: 3,
      audio: [
        {
          name: "Song Title",
          artist: 'Artist Name',
          url: 'https://dl.dropbox.com/s/os8v0ymru1433nn/2%20mix.wav',
          cover: 'https://images.pexels.com/photos/617278/pexels-photo-617278.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
          lrc: '',
          theme: '#46718b'
        },
        {
          name: "Next Song Title",
          artist: 'Next Artist Name',
          url: 'https://dl.dropbox.com/s/os8v0ymru1433nn/2%20mix.wav',
          cover: 'https://images.pexels.com/photos/617278/pexels-photo-617278.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
          lrc: '',
          theme: '#46718b'
        }
      ]
    };
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (this.props.playlist !== prevProps.playlist) {

      const songs = this.props.playlist;
      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 })
      this.setState({sample: 'hello'})
    }
  }

  // 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('audio state', this.state.audio)

  const props = this.state;

    return (
      <Fragment>
      <div className="landing">
      <div className="aplayer-wrap">
        {/* example with detailed props */}
        <ReactAplayer
          {...this.state}
          onInit={this.onInit}
          onPlay={this.onPlay}
          onPause={this.onPause}
        />
        </div>
        </div>
        </Fragment>
    );
  }
}

这是该库中的react-aplayer组件,称为:

import React from 'react';
import PropTypes from 'prop-types';
import APlayer from 'aplayer';
import 'aplayer/dist/APlayer.min.css';
import events from './events';

const capitalize = function(str) {
  return str[0].toUpperCase() + str.slice(1);
};

const eventsPropTypes = events.reduce((acc, event) => {
  acc[`on${capitalize(event)}`] = PropTypes.func;
  return acc;
}, {});

const audioItemShape = PropTypes.shape({
  name: PropTypes.string,
  artist: PropTypes.string,
  url: PropTypes.string,
  cover: PropTypes.string,
  lrc: PropTypes.string,
  theme: PropTypes.string,
  type: PropTypes.string
});

class ReactAplayer extends React.Component {
  static propTypes = {
    onInit: PropTypes.func,
    // belows are the same props with aplayer
    fixed: PropTypes.bool,
    mini: PropTypes.bool,
    autoplay: PropTypes.bool,
    theme: PropTypes.string,
    loop: PropTypes.oneOf(['all', 'one', 'none']),
    order: PropTypes.oneOf(['list', 'random']),
    preload: PropTypes.oneOf(['auto', 'metadata', 'none']),
    volume: PropTypes.number,
    audio: PropTypes.oneOfType([
      audioItemShape,
      PropTypes.arrayOf(audioItemShape)
    ]),
    customAudioType: PropTypes.object,
    mutex: PropTypes.bool,
    lrcType: PropTypes.number,
    listFolded: PropTypes.bool,
    listMaxHeight: PropTypes.string,
    storageName: PropTypes.string,
    // belows are bind event listener
    ...eventsPropTypes
  };

  static defaultProps = {
    onInit() {},
    fixed: false,
    mini: false,
    autoplay: false,
    theme: '#b7daff',
    loop: 'all',
    order: 'list',
    preload: 'auto',
    volume: 0.7,
    mutex: true,
    lrcType: 0,
    listFolded: false,
    storageName: 'react-aplayer-setting'
  };

  componentDidMount() {
    const { onInit, ...restProps } = this.props;

    const control = new APlayer({
      ...restProps,
      container: this.container
    });

    events.forEach(event => {
      const funcName = 'on' + capitalize(event);
      const callback = this.props[funcName];
      if (callback) {
        control.on(event, callback);
      }
    });

    this.control = control;
    onInit(control);
  }

  render() {
    return <div ref={el => (this.container = el)} />;
  }
}

export default ReactAplayer;

1 个答案:

答案 0 :(得分:0)

来回评论之后,看来这可能与React本身如何查看您的道具以及更新的顺序有关。

如果您坚持要通过道具更新状态,那么我建议使用更安全的getDerivedStateFromProps方法,该方法是针对遇到的问题引入的。

Updating state from props(何时/如何使用以及为什么使用此方法)

第二个是仅使用道具来呈现您的播放列表并传递您想要的任何初始播放列表。 (我个人更喜欢这种方法)