JamesBrill / react-speech-recognition

💬Speech recognition for your React app
https://webspeechrecognition.com/
MIT License
657 stars 119 forks source link

Make commands mutable #64

Closed JamesBrill closed 3 years ago

JamesBrill commented 3 years ago

Because the commands prop is an array, its value is always deemed to be changing when either (a) the default value is used or (b) the consumer does not memoize their commands value. The various callbacks and effects depending on commands get re-run on every change, including unrelated changes (e.g. transcript).

This was resulting in a race condition when multiple instances of SpeechRecognition were being rendered. While the transcript was being updated, the new transcripts would cause commands to "change" and re-run the dependent effects, including the one that subscribes and unsubscribes SpeechRecognition to RecognitionManager. As RecognitionManager updates its subscribers of transcript changes, they unsubscribe and resubscribe with a different ID. When having to iterate through many subscribers, the manager would sometimes find that a subscriber no longer existed due to unsubscribing with that old ID after a previous transcript change.

The solution is to stop subscribers from caring about changes to commands. matchCommands, the direct dependent of commands, now accesses it via a mutable ref, just getting whatever the latest value is.

I'm not sure how I feel about this - it feels like a misuse of hooks. Besides hashing commands and comparing that with its old value, this is the best I can come up with for now.