【发布时间】:2021-12-10 14:54:50
【问题描述】:
我正在尝试使用 React Webcam 实现视频录制。录制视频后,应setSelectedFile。然后selectedFile 要么通过axios 发布方法上传到数据库,要么被另一个记录替换。每次录制后,用户应该可以查看最新的。
UI 按我的意愿工作,在录制过程中显示录制屏幕,在录制完成时显示录制文件。
我遇到的问题是我的selectedFile(需要通过 axios 发布)的状态值总是比它应该的值落后 1 个渲染。因此,在第一次录制后,selectedFile 未定义,在第二次录制后,设置为selectedFile 的文件实际上是第一次录制,依此类推。如果我刷新浏览器,整个过程会自行重置并重新开始循环。
我尝试从useEffect 调用setSelectedFile() 而没有useEffect (尽管如果我正确理解了useEffect,我认为我不应该在这里需要它,因为我不希望每个人都执行此操作使成为)。无论哪种方式,它似乎都不会对程序的行为产生任何影响。
setSelectedFile 调用我做错了什么吗?就像我说的那样,除了所选文件在它应该是 1 渲染(记录/停止记录)之外,一切工作正常。
我在下面附上我的代码。
const RecordNow = () => {
const[details, setDetails] = useState({consent:false,
idConfirmed:false,
label:"",
roundId:""})
const {
startRecording,
stopRecording,
mediaBlobUrl,
} = useReactMediaRecorder({ video: true, audio: true, blobPropertyBag: {
type: "video/mp4"
} });
const [curStatus, setCurStatus] = useState(true);
const [selectedFile, setSelectedFile] = useState([null]);
const [isFilePicked, setIsFilePicked] = useState(false);
useEffect(()=>{
setSelectedFile();
},[])
// Handles upload of selected file via axios
const uploadToDB =()=>{
console.log("Called")
setDetails(prevDetails=>({
...prevDetails,
consent:true,
idConfirmed:true,
label:"test_Label"
}));
axios.post(process.env.REACT_APP, details)
.then(res=>{
console.log("Res:", res)
const data = new FormData();
data.append("file", selectedFile)
console.log("SelectedFile", selectedFile)
axios.post(`${process.env.REACT_APP}}/file/upload`, data,
{
headers:{
"Content-Type":"multipart/form-data"
}
})
.then(res=>{
console.log("Data: ",res.data)
console.log("success")
})
.catch((e)=>{
console.log("Error", e)
})
})
}
// Starts recording of new video
const startedRec = () => {
startRecording();
setIsFilePicked(false)
setCurStatus(false);
}
// Stops recording of new video and creates blob
const stoppedRec = async () => {
stopRecording();
const videoBlob = await fetch(mediaBlobUrl).then(r => r.blob());
console.log("MediaBlob URL", mediaBlobUrl)
const url = new Blob ([videoBlob]);
//Creates a video file and filename
const videoFile = new File([videoBlob], `wardround.${"mp4"}`, { type: "video/mp4" })
console.log('Video File:', videoFile);
console.log('Blob:', url);
setSelectedFile(videoFile)
console.log("Selected file", selectedFile)
setCurStatus(true);
setIsFilePicked(true)
}
// Handles input change and assigns input value to selectedFile variable
const changeHandler = (event) => {
setSelectedFile(event.target.files[0]);
setIsFilePicked(true);
setDetails(prevDetails=>({
...prevDetails,
consent:true,
idConfirmed:true,
label:"test_Label"
}));
};
return (
<div>
{!isFilePicked ?
<div className='player-wrapper'>
<Webcam audio={false} height={400} width={500}/>
</div> :
<video height="400" width="500" controls>
<source src={mediaBlobUrl}/>
</video>
}
{curStatus ?
<span>
<button id="video-record" onClick={startedRec}>Record Video</button>
</span>
:
<span>
<button id="video-record" onClick={stoppedRec}>Stop Recording</button>
</span>
}
{!isFilePicked ?
<span>
<label
className="file-upload"
htmlFor="file-upload">
UPLOAD VIDEO
</label>
<input
id="file-upload"
type="file"
onChange={changeHandler}
/>
</span> :
<span>
<label
className="file-upload"
htmlFor="confirm-upload">
SUBMIT VIDEO
</label>
<input
id="confirm-upload"
type="submit"
onClick={() => uploadToDB()}
/>
</span>}
</div>
);
};
export default RecordNow
【问题讨论】:
-
为 useEfect 提供正确的依赖关系,因此它会随着该状态的每次变化而更新
-
每当您看到“1 个渲染落后于它应该是什么”时,请记住设置状态是异步的。例如。不能期望您的
setSelectedFile(videoFile); console.log("Selected file", selectedFile)记录正确的值,因为该状态更改可能尚未发生。 -
@DBS。行。这就说得通了。您能否建议任何方法来允许在继续之前发生这种“状态”变化?
-
在下面查看我对@SlothOverlord 回答的评论。