Как перехватить наблюдаемые обновления Mobx в постоянном компоненте NextJS React Audio Player?

У меня есть приложение для реакции аудиоплеера на стороне сервера.

Используя пользовательский _app.js NextJS, у меня есть постоянный компонент AudioPlayer, в котором я хочу вызывать внутреннюю функцию this.play(mp3url) всякий раз, когда @observable playerData = {} изменяется в хранилище mobx.

Я успешно нажимал кнопки на других компонентах в моем приложении, обновляя playerData, когда это необходимо.

Но я не могу обнаружить эти обновления внутри моего компонента AudioPlayer, поэтому я могу установить его состояние и вызвать this.play(mp3url), чтобы начать воспроизведение звука.

страницы/_app.js

import initializeStore from '../stores/stores';

export default class MyApp extends App {

  static async getInitialProps(appContext) {
    const mobxStore = initializeStore();
    appContext.ctx.mobxStore = mobxStore;
    const appProps = await App.getInitialProps(appContext);
    return {
      ...appProps,
      initialMobxState: mobxStore,
    };
  }

  constructor(props) {
    super(props);
    this.mobxStore = props.initialMobxState;
  }

  render () {
    const { Component, pageProps } = this.props
    return (
      <Provider {...this.mobxStore}>
          <Component {...pageProps} />
        { this.mobxStore.playerStore.playerActive && <AudioPlayer /> }
      </Provider>
    )
  }
}

компоненты/AudioPlayer.js

import ReactPlayer from 'react-player'
import { inject, observer } from 'mobx-react'

@inject('playerStore')
@observer
class Player extends Component{
    constructor(props) {
        super(props)
        this.state = {
            url: null,
            image: null
        }
    }
    componentWillUpdate(nextProps) {
        this.setState({
            url: nextProps.playerStore.playerData.url,
            image: nextProps.playerStore.playerData.image
        }, () => { this.play(this.state.url) })
    }

    // ...Other react-player functions

    render() {
        <ReactPlayer 
        {/* ...required props... */}
        />
    }
}

Так как же заставить этот постоянный аудиоплеер обнаруживать изменения в наблюдаемом mobx для воспроизведения URL-адресов аудио?

На данный момент componentWillReceiveProps, componentWillUpdate или componentDidUpdate не вызываются. componentDidMount вызывается ровно один раз, как и ожидалось, когда я устанавливаю @observable playerActive = true


person checkmate101    schedule 05.10.2019    source источник


Ответы (1)


Удалось разобраться. Это было вызвано двумя проблемами.

  1. Согласно документам Mobx

Функция наблюдателя/декоратор может использоваться для превращения компонентов ReactJS в реактивные компоненты. Он оборачивает функцию рендеринга компонента в mobx.autorun, чтобы гарантировать, что любые данные, которые используются во время рендеринга компонента, вызывают повторный рендеринг при изменении. Он доступен через отдельный пакет mobx-react.

Наблюдаемое хранилище необходимо использовать в функции рендеринга компонента-наблюдателя, чтобы компонент реагировал на его изменения. Поэтому я добавил их в компонент AudioPlayer вместо того, чтобы брать его из собственного состояния.

  1. Мне не хватало этой важной строки кода в конструкторе pages/_app.js, которая правильно инициализировала бы хранилище mobx на стороне клиента.
this.mobxStore = isServer ? props.initialMobxState : initializeStore(props.initialMobxState)

Теперь компонент AudioPlayer реагирует на каждое обновление наблюдаемого объекта mobx, и я могу обрабатывать любую дальнейшую необходимую логику в componentWillUpdate/componentDidUpdate.

person checkmate101    schedule 06.10.2019
comment
Спасибо большое за ваш пример. У меня есть работающий сайт о музыке, который я хочу превратить в React. Чтобы сохранить свои SEO-преимущества, я переключил тест React Router на NextJS. Но мне определенно нужно, чтобы аудиоплеер никогда не останавливался на разных страницах. Я проверю это и свяжусь с вами, если мне понадобится помощь. - person KeitelDOG; 25.12.2019
comment
Да, я сделал это, как только я поместил Player в _app.js, NextJS никогда не избавится от него. Поэтому я использую реквизиты функций с событиями на _app.js для обновления плеера всякий раз, когда мне нужно. - person KeitelDOG; 10.02.2020