Custom React Hook for Text-to-Speech Synthesis
This challenge asks you to build a custom React hook, useSpeechSynthesis, that encapsulates the functionality of the Web Speech API's Speech Synthesis. This hook will allow developers to easily integrate text-to-speech capabilities into their React applications, making content more accessible and engaging.
Problem Description
You need to create a reusable React hook named useSpeechSynthesis that provides an interface for controlling text-to-speech synthesis. The hook should abstract away the complexities of the SpeechSynthesis API, allowing users to speak text, control speaking, and get the current speaking status.
Key Requirements:
speak(text: string)function: A function to initiate speech synthesis for a given string of text.cancel()function: A function to stop any ongoing speech synthesis.isSpeakingboolean state: A state variable indicating whether speech synthesis is currently active.- Support for voices: The hook should ideally allow selecting a voice from available system voices.
- Error handling: Basic error handling for cases where the Speech Synthesis API is not supported.
Expected Behavior:
When speak() is called with text, the hook should:
- Check if the browser supports
speechSynthesis. - Create a
SpeechSynthesisUtteranceobject with the provided text. - If voices are available, select a default or specified voice.
- Initiate speaking using
window.speechSynthesis.speak(). - Update
isSpeakingtotruewhen speaking starts andfalsewhen it finishes or is cancelled.
When cancel() is called, the hook should:
- Stop any ongoing speech using
window.speechSynthesis.cancel(). - Set
isSpeakingtofalse.
Edge Cases to Consider:
- Browser Support: The
speechSynthesisAPI might not be available in all browsers or environments. The hook should gracefully handle this. - No Voices Available: Some systems might not have any speech synthesis voices installed.
- Empty Text: What happens when
speak()is called with an empty string? - Cancelling while not speaking: Calling
cancel()when nothing is being spoken should not cause errors.
Examples
Example 1: Basic Usage
import React, { useEffect } from 'react';
import { useSpeechSynthesis } from './useSpeechSynthesis'; // Assuming hook is in this file
function App() {
const { speak, cancel, isSpeaking } = useSpeechSynthesis();
const handleSpeak = () => {
speak('Hello, world!');
};
return (
<div>
<button onClick={handleSpeak} disabled={isSpeaking}>
Speak
</button>
<button onClick={cancel} disabled={!isSpeaking}>
Cancel
</button>
{isSpeaking && <p>Speaking...</p>}
</div>
);
}
export default App;
Explanation:
The useSpeechSynthesis hook is called, returning speak, cancel, and isSpeaking. Clicking the "Speak" button calls speak('Hello, world!'), initiating text-to-speech. The "Cancel" button calls cancel(), stopping the speech. The isSpeaking state dynamically updates the UI.
Example 2: Handling Browser Incompatibility
import React from 'react';
import { useSpeechSynthesis } from './useSpeechSynthesis';
function App() {
const { speak, cancel, isSpeaking, isSupported } = useSpeechSynthesis();
if (!isSupported) {
return <p>Speech synthesis is not supported in your browser.</p>;
}
return (
<div>
<button onClick={() => speak('This is a test.')} disabled={isSpeaking}>
Speak
</button>
<button onClick={cancel} disabled={!isSpeaking}>
Cancel
</button>
</div>
);
}
export default App;
Explanation:
The hook now also returns an isSupported boolean. If the browser doesn't support speechSynthesis, a message is displayed, and the buttons are not rendered.
Constraints
- The solution must be implemented in TypeScript.
- The hook should only rely on native browser APIs (
SpeechSynthesis,SpeechSynthesisUtterance) and React hooks. No external libraries for speech synthesis are allowed. - The
speakfunction should ideally handle basic text sanitization if necessary (though for this challenge, assume input text is valid for speech synthesis). - The
isSpeakingstate should update accurately based on the lifecycle of the speech synthesis process (start, end, cancellation).
Notes
- You can access available voices via
window.speechSynthesis.getVoices(). Note that these voices are often loaded asynchronously. You might need to listen for thevoiceschangedevent. - Consider how you will manage the
SpeechSynthesisUtteranceobject within the hook's lifecycle. - Think about how to clean up any event listeners or prevent memory leaks when the component using the hook unmounts.
- The initial implementation can focus on the core
speakandcancelfunctionality, with optional enhancements for voice selection and more robust error handling.