if I use the following code, the page can work correct.
{videoRefs.current.map((videoRef, index) => ( (
<div className='stream' key={videoRef.deviceId}>
<video ref={videoRef.ref} autoPlay playsInline></video>
<div className='overlay'><p>{devices[index]?.label || `鏡頭 ${index + 1}`}</p></div>
</div>
)))}
But when I add isVideoVisible[videoRef.deviceId], my video component will go wrong and just display the side bar
{videoRefs.current.map((videoRef, index) => ( isVideoVisible[videoRef.deviceId] && (
<div className='stream' key={videoRef.deviceId}>
<video ref={videoRef.ref} autoPlay playsInline></video>
<div className='overlay'><p>{devices[index]?.label || `鏡頭 ${index + 1}`}</p></div>
</div>
)))}
import React, { useEffect, useRef, useState } from 'react';
import './App.css';
import Switch from '@mui/material/Switch';
function App() {
const videoRefs = useRef([]); // 使用空數組來儲存 video 元素的引用
const label = { inputProps: { 'aria-label': 'Switch demo' } };
const [devices, setDevices] = useState([]); // 用於存儲設備列表
const [streams, setStreams] = useState({}); // 存儲每個設備的流
const [isVideoVisible, setIsVideoVisible] = useState({});
// TODO: 處理開關變更事件,開啟一個鏡頭時,只能出現在一個視窗中,其他 conponent 需要關閉
const handleSwitchChange = (deviceId, checked) => {
if (checked) {
navigator.mediaDevices.getUserMedia({video: { deviceId: deviceId }})
.then(stream => {
const videoRef = videoRefs.current.find(ref => ref.deviceId === deviceId);
if (videoRef && videoRef.ref.current) {
videoRef.ref.current.srcObject = stream; // 設置視頻流
setStreams(prevStreams => ({
...prevStreams,
[deviceId]: stream,
}));
setIsVideoVisible(prev => ({ ...prev, [deviceId]: true })); // 顯示視頻
}
}).catch(err => {
console.error('無法存取攝像頭:', err);
});
} else {
if (streams[deviceId]) {
console.log('關閉前的 stream:', streams);
streams[deviceId].getTracks().forEach(track => track.stop()); // 停止流
setStreams(prevStreams => {
const newStreams = { ...prevStreams };
delete newStreams[deviceId]; // 移除流
return newStreams;
});
setIsVideoVisible(prev => ({ ...prev, [deviceId]: false })); // 隱藏視頻
// 清除視頻元素的 srcObject
const videoRef = videoRefs.current.find(ref => ref.deviceId === deviceId);
if (videoRef && videoRef.ref.current) {
videoRef.ref.current.srcObject = null; // 清除視頻元素的 srcObject
}
}
console.log('關閉後剩餘的流:', streams);
}
};
useEffect(() => {
navigator.mediaDevices.enumerateDevices()
.then(devices => {
const videoDevices = devices.filter(device => device.kind === 'videoinput');
setDevices(videoDevices);
console.log('找到的攝像頭:', videoDevices);
// 初始化 videoRefs
videoRefs.current = videoDevices.map(device => ({ deviceId: device.deviceId, ref: React.createRef() }));
videoDevices.forEach(device => {
navigator.mediaDevices.getUserMedia({
video: { deviceId: device.deviceId }
}).then(stream => {
const videoRef = videoRefs.current.find(ref => ref.deviceId === device.deviceId);
console.log('videoRef',videoRef);
handleSwitchChange(device.deviceId, true);
if (videoRef && videoRef.ref.current) {
videoRef.ref.current.srcObject = stream;
setStreams(prevStreams => ({
...prevStreams,
[device.deviceId]: stream,
}));
}
}).catch(err => {
console.error('無法存取攝像頭:', err);
});
});
})
.catch(err => {
console.error('無法取得媒體設備:', err);
setLoading(false); // 如果出現錯誤,則停止加載
});
}, []);
return (
<>
<div className='sidebar'>
<h2>LUXGroup</h2>
{devices.map((device, index) => (
<div key={device.deviceId}>
{device.label || `鏡頭 ${index + 1}`}
<Switch
{...label}
defaultChecked
onChange={(e) => handleSwitchChange(device.deviceId, e.target.checked)}
/>
</div>
))}
</div>
<div className='stream-container'>
{console.log('hihi')}
{videoRefs.current.map((videoRef, index) => ( (
<div className='stream' key={videoRef.deviceId}>
<video ref={videoRef.ref} autoPlay playsInline></video>
<div className='overlay'><p>{devices[index]?.label || `鏡頭 ${index + 1}`}</p></div>
</div>
)))}
{/* isVideoVisible[videoRef.deviceId] */}
</div>
</>
);
}
export default App;
I expected that when I use isVideoVisible[videoRef.deviceId] ,I can handle the page component by the switch