Я реорганизую ранее созданное приложение React на основе классов, чтобы оно работало с использованием хуков. Это простое приложение для драм-машины. Я использую .map, чтобы заполнить страницу массивом объектов, содержащих данные для охвата ударной панели и связанного с ней звука.
{soundBank.map((sound) => (
<DrumPad
key={sound.id}
id={sound.id}
letter={sound.letter}
src={sound.src}
handleDisplay={handleDisplay}
/>
))}
После рефакторинга кажется, что все работает, кроме воспроизведения отдельных ударных площадок с использованием OnKeyPress. Вот как мой код выглядел как компонент на основе классов:
handleKeyPress = event => {
if (event.keyCode === this.props.letter.charCodeAt()) {
this.audio.play();
this.audio.currentTime = 0;
this.props.handleDisplay(this.props.id);
}
render() {
return (
<div
className="drum-pad"
id={this.props.id}
onClick={this.handleClick.bind(this)}
onKeyPress={this.handleKeyPress.bind(this)}
>
<h1>{this.props.letter}</h1>
<h2>{this.props.id}</h2>
<audio
className="clip"
id={this.props.letter}
src={this.props.src}
ref={ref => (this.audio = ref)}
></audio>
</div>
);}
Вот как он выглядит как функциональный компонент:
let audio = useRef(null);
const handleKeyPress = (event) => {
if (event.keyCode === props.letter.charCodeAt()) {
audio.play();
audio.currentTime = 0;
props.handleDisplay(props.id);
}
};
return (
<div
className="drum-pad"
id={props.id}
onClick={handleClick}
onKeyPress={handleKeyPress}
>
<h1>{props.letter}</h1>
<h2>{props.id}</h2>
<audio
className="clip"
id={props.letter}
src={props.src}
ref={(ref) => (audio = ref)}
></audio>
</div>);
Я пытался использовать useCallback, а также создание состояния для аудио, но я не могу заставить его работать. Когда страница загружена, первое нажатие клавиши воспроизводит звук, но любое нажатие после этого, и я получаю ошибку:
Uncaught TypeError: Cannot read property 'play' of null
at HTMLDocument.handleKeyPress
При проверке ошибок с помощью console.log кажется, что всякий раз, когда нажата клавиша, функция handleKeyPress вызывается 9 раз (по одному разу для каждой ударной панели). Как сделать так, чтобы при нажатии одной клавиши активировалась только одна указанная c ударная панель, и как я могу убедиться, что звук не возвращается в ноль? Эта проблема также может быть связана с моим использованием реф. Я делаю это, чтобы выучить хуки (и реагировать в целом), поэтому любые указатели в правильном направлении будут высоко оценены.
РЕШЕНИЕ
Вот мое решение основываясь на выбранном ответе Александра Ковпашко:
const audio = useRef(null);
const handleKeyPress = useCallback((event) => {
if (event.keyCode === props.letter.charCodeAt()) {
audio.current.play();
audio.current.currentTime = 0;
props.handleDisplay(props.id);
}}, []);
<audio
className="clip"
id={props.letter}
src={props.src}
ref={audio}
></audio>