Let's say I am building a simple audio player with xstate.
My initial machine is like this:
const audioMachine = createMachine({
id: 'audio_player',
initial: 'pause',
states: {
pause: {
on: {
START_PLAY: 'play',
},
},
play: {
on: {
STOP_PLAY: 'pause',
},
},
},
})
I intend to customize my Audio player therefore I don't use the default audio tag.
Now I have two directions to integrate it.
- Make my machine reacts to
audioelement. - Make the
audioelement reacts to my machine.
My first attempt: make my machine reacts to audio element.
const AudioPlayer = ({ src }) => {
const audioRef = useRef(null);
const [state, send] = useMachine(audioMachine);
useEffect(() => {
const audio = new Audio(audioSrc)
audioRef.current = audio
audio.addEventListener('play', () => send('START_PLAY'));
audio.addEventListener('pause', () => send('STOP_PLAY'));
// return ....
}, [send]);
return (
<div>Play and Pause Button should be here</div>
);
};
export default AudioPlayer;
I don't like this version, because I feel that the my state machine is not controlling the audio player.
My gut is that the machine should control the player. When the START_PLAY event is fired by machine, the audio should play as an side-effect. But I am not sure.