Lodott1
Lodott1

Reputation: 105

Sequential async functions

Trying to update my state sequentially with async await. First state function does not update state before the next function runs, which is dependent on the first function's state change.

I've tried both promises and async await, but the first state function will not update before the next function.

let setAudio = () => {
    return new Promise(resolve => {
      if(state.currentTrackIndex === null) {
        setState(state=>({...state, audioPlayer: new Audio()}))
        setTimeout(() => {
            resolve('done');
        }, 1000);
      } else {
        setState(state=>({...state}))
        setTimeout(() => {
            resolve('done');
        }, 1000);
      }
    })
  }
  let setTrack = (index) => {
    return new Promise(resolve => {
      if (index === state.currentTrackIndex) {
        togglePlay();
        setTimeout(() => {
            resolve('done');
        }, 1000);
      } else {
        state.audioPlayer.pause()
        state.audioPlayer = new Audio(state.tracks[index].file);
        state.audioPlayer.play();
        setState(state => ({ ...state, currentTrackIndex: index, isPlaying: true }));
        setTimeout(() => {
            resolve('done');
        }, 1000);
      }
    })
  }
  async function playTrack(index){
    try {
      let result1 = await setAudio()
      let result2 = await setTrack(index)
      return result2;
    }
    catch(error){
      console.log(error)
    }
  }

setAudio: I'm first checking for an audio object in state.audioPlayer. If the current state.currentTrackIndex is null (which is the default value before starting the music player), I want the state to be updated with an audio object in state.audioPlayer. If there currently exists an object, I keep the state. The reason for this: The app is made with GatsbyJS, so setting an audio object on initial state will not work, the components needs to be rendered first.

setTrack: If I click the current track, it should pause the audio player, if I click another track, the audio object should first pause, then be populated with the new audio object, and then play the new audio. In addition to setting the new currentTrackIndex.

playTrack: The goal here is to run the code sequentially, first checking for the audio object, then playing the correct audio.

Upvotes: 0

Views: 220

Answers (1)

therobinkim
therobinkim

Reputation: 2568

  1. Don't modify this.state directly. For example, you might want to refactor this line:

    state.audioPlayer = new Audio(state.tracks[index].file);
    

    Try using this.setState() instead. https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly

  2. The only time at which you know this.setState has finished executing is in the 2nd argument you provide this.setState. Instead of using Promises that resolve after a 1000ms timeout, does providing a 2nd argument to this.setState help with any of your issues? Or do you want to try putting some of your logic in componentDidMount() instead as suggested by the documentation? https://reactjs.org/docs/react-component.html#setstate

Upvotes: 1

Related Questions