- The Context
- React Mic and Recording
- The Problem: To Transcribe or Not to Transcribe?
- Key Considerations
- The Final Solution
- Conclusion
When developing the multifunctional AI assistant app, I encountered a common dilemma in React: should I use useState or useRef to manage a piece of logic? In this article, I’ll walk you through my decision process and explain why I opted for useRef in a scenario involving user speech transcription.
The Context
The app has two key buttons: a play/stop toggle button and a reset button. Here’s the desired behavior:
- When the user presses the stop button, their speech is transcribed and displayed in a text box.

- When the reset button is pressed, the recording is cleared and not sent for transcription, since transcription costs both time and money.

However, both buttons stop the recording, so I needed a way to distinguish which button triggered the stop action. This would determine whether or not the transcription should occur.
React Mic and Recording
I used the react-mic library to handle speech recording. The library captures the user’s speech and provides it as an audio blob. Typically, you use the component like this:
<ReactMic
record={isRecording}
onStop={handleStop}
{...otherProps}
/>
When isRecording is set to false, the recording stops and handleStop is triggered, receiving the audio blob as an argument.
const handleStop = (returnedBlob) => {
// Process the blob
}
Since both the stop and reset buttons stop the recording, I needed a way to determine if the transcription should happen. This led to the decision between useState and useRef.
The Problem: To Transcribe or Not to Transcribe?
I wanted to set a flag (shouldTranscribe) that would:
- Trigger transcription only when the stop button is pressed.
- Prevent transcription when the reset button is clicked.
The core issue is that both buttons set the recording state to false, which in turn triggers handleStop. To avoid sending the recording for transcription when the reset button is pressed, I needed a flag that could differentiate between the two actions.
Key Considerations
-
Avoid Unnecessary Re-renders
useStatetriggers a component re-render whenever its value is updated. This behavior is unnecessary here because changingshouldTranscribedoesn’t affect the UI. It’s a purely logical decision: whether or not to send the recording for transcription. On the other hand,useRefcan hold a mutable value without triggering a re-render. This makes it perfect for managing non-UI-related logic like a flag that determines whether transcription should happen. -
Immediate Access to the Updated Value
useStateupdates are asynchronous, meaning that if I useduseStateto toggleshouldTranscribe, the new value wouldn’t be immediately available during the stop event handling. In contrast,useRefprovides immediate access to the updated value, which is essential for making synchronous decisions, like whether to transcribe the audio.
The Final Solution
Here’s the solution I implemented using useRef:
const shouldTranscribeRef = useRef(false)
const handleStart = () => {
setIsRecording(true)
}
const handleStop = () => {
shouldTranscribeRef.current = true // Transcription will happen
setIsRecording(false)
}
const handleReset = () => {
shouldTranscribeRef.current = false // No transcription
setIsRecording(false)
// Other code omitted
}
const handleTranscribe = async (returnedBlob) => {
if (shouldTranscribeRef.current) {
// Send the blob for transcription
}
}
return (
<div>
<ReactMic
record={isRecording}
onStop={handleTranscribe}
{...otherProps}
/>
{isRecording ? (
<button onClick={handleStop}>
Stop
</button>
) : (
<button onClick={handleStart}>
Play
</button>
)}
<button onClick={handleReset}>
Send
</button>
</div>
)
This way, I managed to achieve the designed behaviour shown in The Context section.
Conclusion
In this case, using useRef was a better fit than useState because it:
- Avoided unnecessary re-renders.
- Provided immediate access to the updated value.
This pattern worked well in my AI assistant app, where I needed to manage non-UI logic efficiently. When deciding between useState and useRef, consider whether you need reactivity (in which case useState is appropriate) or just an instance variable (where useRef is better suited).
For more information, see React documentation on refs.