【发布时间】:2021-05-24 06:14:41
【问题描述】:
对于我在 React 中构建的网络应用程序,我需要录制音频并能够以某种方式将录制的音频置于应用程序的全局状态中,以便我可以在应用程序的不同组件中使用和操作录制的音频。
我的全局状态是使用 React Hooks 设置的(使用 useReducer、createContext、useContext 制作和管理),我相信 Hooks 仅适用于功能组件,而不适用于类组件。
所以我遇到的问题是,我为使浏览器麦克风工作而遵循的每个教程都使用类组件(如下面的代码),而不是功能组件。我假设这是有充分理由的,因为当我尝试将这些类组件转换为功能组件时,我收到错误:“无法读取 'undefined' 的属性 'finish'”
有没有办法获取此音频数据 (blobURL) 并将其传递给我的全局状态?
或者(理想情况下),有没有办法使用麦克风在功能组件而不是类组件中录制音频?
import MicRecorder from "mic-recorder-to-mp3";
import React from "react";
const Mp3Recorder = new MicRecorder({ bitRate: 128 });
class AudioRecorder extends React.Component {
constructor(props) {
super(props);
window.AudioContext = window.AudioContext || window.webkitAudioContext;
this.state = {
isRecording: false,
isPaused: false,
blobURL: "",
isBlocked: false
};
}
startRecording = () => {
if (this.state.isBlocked) {
console.log("Please give permission for the microphone to record audio.");
} else {
Mp3Recorder.start()
.then(() => {
this.setState({ isRecording: true });
})
.catch(e => console.error(e));
}
};
stopRecording = () => {
this.setState({ isRecording: false });
Mp3Recorder.stop()
.getMp3()
.then(async ([buffer, blob]) => {
const blobURL = URL.createObjectURL(blob)
this.setState({
blobURL: blobURL,
isRecording: false
});
})
.catch(e => console.log(e));
};
checkPermissionForAudio = () => {
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function(constraints) {
// First get ahold of the legacy getUserMedia, if present
var getUserMedia =
// navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// Some browsers just don't implement it - return a rejected promise with an error
// to keep a consistent interface
if (!getUserMedia) {
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
}
// Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
return new Promise(function(resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(stream => {
this.setState({ isBlocked: false });
})
.catch(err => {
this.setState({ isBlocked: true });
console.log("Please give permission for the microphone to record audio.");
console.log(err.name + ": " + err.message);
});
};
componentDidMount() {
this.checkPermissionForAudio();
}
render() {
const { isRecording } = this.state;
return (
<React.Fragment>
<button
onClick={this.startRecording}
className="mr-3 add-collec-btn"
disabled={isRecording}
>
Record
</button>
<button
onClick={this.stopRecording}
className="mr-3 delete-btn"
disabled={!isRecording}
>
Stop
</button>
<audio
ref="audioSource"
controls="controls"
src={this.state.blobURL || ""}
/>
</React.Fragment>
);
}
}
export default AudioRecorder;
更新: 这就是我在应用程序中设置 Context 的方式以及通过代码提供的方式。在我的商店文件夹中,我有三个文件:Context.js、GlobalStateProvider 和 useGlobalState。
Context.js
import { createContext } from 'react';
const Context = createContext({});
export default Context;
GlobalStateProvider.js
这包含了我的 App.js 文件中的所有内容
import React from 'react';
import useGlobalState from './useGlobalState';
import Context from './Context';
const GlobalStateProvider = ({ children }) => {
return (
<Context.Provider value={useGlobalState()}>{children}</Context.Provider>
);
}
export default GlobalStateProvider;
使用GlobalState.js
import { useReducer } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'SETISRECORD':
return {
...state,
isRecording: action.payload
}
case 'SETISBLOCKED':
return {
...state,
isBlocked: action.payload
}
case 'setBlobURL':
return {
...state,
blobURL: action.payload
}
default: {
return state;
}
}
};
const useGlobalState = () => {
const [globalState, globalDispatch] = useReducer(reducer, {
isRecording: false,
isBlocked: false,
blobURL: '',
});
return { globalState, globalDispatch };
}
export default useGlobalState;
然后我在功能组件中与我的全局状态交互,如下所示:
const functionalComponent = () => {
const { globalState, globalDispatch } = useContext(Context);
return (
[code]
);
}
【问题讨论】:
-
基于类的组件仍然可以访问 React 上下文,尽管它不是通过
useContextReact 钩子,而是通过Context.Consumer。您能否更新您的问题以包含您的上下文代码以及它是如何提供给您的应用程序的? -
@DrewReese 感谢您的回复!我已更新问题以包含我的上下文代码
标签: reactjs