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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用componentDidUpdate()和React-APlayer库更新状态。相关的知识,希望对你有一定的参考价值。

我正试图用从父组件中的fetch请求中接收到的数据更新状态。我使用的是'react-aplayer'库 (https:/github.comMoePlayerreact-aplayer。)作为一个音频播放器。

我能够将歌曲硬编码到播放列表中,如下面的'this.state.audio'所示。 然而,当我试图通过componentDidUpdate()方法将这些数据改为通过道具接收的数据时,我无法将State设置为新数据。当我控制台.日志'this.state.audio'查看数据时,我得到两条消息:第一条是硬编码的播放列表信息,下一条是我从fetch请求中接收到的数据。

我如何用新的数据更新状态,使其取代硬编码的数据?

这是我的组件。

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;

答案

经过来回的评论,似乎这可能是React本身如何看待你的道具和更新顺序的问题。

如果你坚持从道具中更新你的状态,那么我建议使用更安全的方法。getDerivedStateFromProps 方法,该方法是为了解决你所面临的问题而引入的。

从道具更新状态 (何时使用,为何有此方法)

第二种方法是只用道具来渲染你的播放列表,然后传入你喜欢的任何初始播放列表。(我个人比较喜欢这种方法)

以上是关于用componentDidUpdate()和React-APlayer库更新状态。的主要内容,如果未能解决你的问题,请参考以下文章

在 componentDidUpdate 中无法访问的状态

componentDidUpdate 中的 prevState 是 currentState?

mapStateToProps,但未调用componentDidUpdate

在ComponentDidUpdate中出现奇怪的条件行为。

componentDidUpdate 没有触发

如何处理 ComponentDidUpdate 中的异步数据?