我如何在React应用程序中创建一个单独的动态窗口?



我的React应用程序包含视频聊天功能(通过Twilio)。用户转到仪表板,然后单击按钮开始呼叫。这提示要实例化并显示VideoCall组件。在实例化时,它连接到后端Twilio服务以获取访问令牌,然后连接到Twilio以创建调用,设置事件处理程序等。

目前我在仪表板内的div显示视频窗口,但我希望他们出现在一个弹出窗口,而不是。我试过使用React -new-window,也试过React Portals,但我不知道我在做什么来让它工作。

目前我有以下Dashboard组件:

function Dashboard(props) {
const { displayInfo} = props
const [ callInitiated, setCallInitiated ] = useState(false)
const initCall = () => {
setCallInitiated(true)
}
return (
<div id="dashboard">
{callInitiated ? <VideoCall displayInfo={displayInfo} /> : null }
<div> ...rest of dashboard, including button which calls 'initCall' on being clicked... </div>
</div>
)
}
export default Dashboard

我的VideoCall分量是:

const Video = require('twilio-video');
// Get access token from backend service
async function getAccessToken(identity) {
const url = `${process.env.REACT_APP_TWILIO_TOKEN_SERVICE}?identity=${identity}`;
try {
const response = await axios.get(`${url}`, AXIOS_HEADERS);
return response.data.accessToken;
} catch {
return null;
}
}
// VideoCall component
function VideoCall(props) {
const { displayInfo} = props
// Connect to Twilio server function to get access token
getAccessToken('Tester')
.then((token) => {
Video.connect(token, {
name: 'Test room'
})
.then(room => {
participantConnected(room.localParticipant);
room.participants.forEach(participantConnected);
room.on('participantConnected', participantConnected);
room.on('participantDisconnected', participantDisconnected);
room.once('disconnected', error => room.participants.forEach(participantDisconnected))
})
});
function participantConnected(participant) {

const div = document.createElement('div');
div.id = participant.sid;

participant.on('trackSubscribed', track => trackSubscribed(div, track));
participant.on('trackUnsubscribed', trackUnsubscribed);

participant.tracks.forEach(publication => {
trackSubscribed(div, publication.track);
});
if(participant.identity === 'Tester') {
document.getElementById('myVideoWindow').appendChild(div)
}

}

function participantDisconnected(participant) {
document.getElementById(participant.sid).remove();
}

function trackSubscribed(div, track) {
div.appendChild(track.attach());
}

function trackUnsubscribed(track) {
track.detach().forEach(element => element.remove());
}
return (
<div id="callWrapper" className="callOuterWrapper">
<div className="titleBar">
<h1 className="pageHeader">Calling {displayInfo.receiverName}</h1>
</div>
<div className="videoRoom">
<div id="myVideoWindow" className="callWindow"></div>
<div className="callInfo"> ...this will contain info on call status... </div>
<div id="receiverWindow" className="callWindow"></div>
</div>
</div>
)
}
export default VideoCall
到目前为止,这是有效的。用户单击按钮,视频窗口出现在仪表板的顶部,如预期的那样。

现在我想把VideoCall组件拉到一个单独的窗口中(以便用户在调用时仍然可以看到仪表板)。

我尝试了package react-new-window,它只涉及将VideoCall包装在NewWindow中。我试着在Dashboard组件内包装它:

<div id="dashboard">
{callInitiated ? <NewWindow><VideoCall displayInfo={displayInfo} /></NewWindow> : null }
<div> ...rest of dashboard, including button which calls 'initCall' on being clicked... </div>
</div>

,当这不起作用时,我尝试在VideoCall组件内包装:

<NewWindow>
<div id="callWrapper" className="callOuterWrapper">...</div>
</NewWindow>

在这两种情况下,这显示了新的窗口与空callWrapperdiv;然而,一旦到达document.getElementById('myVideoWindow').appendChild(div),它就无法找到div。被引用的DOM似乎是仪表板窗口而不是新窗口的DOM(此外,任何console.log命令都被记录到原始窗口的控制台,而不是新窗口)。

然后我试着拆开NewWindow代码并创建我自己的定制版本,但我对它的工作原理了解不够,无法让它做我需要的事情。

那么,是否有一种方法可以从其中的组件访问新窗口的DOM ?或者我应该采取不同的方法?

这里是Twilio开发者布道者。

直接使用本地DOM方法访问DOM,如document.getElementById,在React中有点不受欢迎。React本身应该负责从DOM中添加和删除东西。

我写了一篇关于如何用React构建视频聊天的文章,介绍了如何在不直接访问DOM的情况下将参与者添加到页面中。

我建议你看一下,也许更新你的应用程序,这样你就不必使用document.getElementById,然后希望<NewWindow>组件应该像广告那样工作。

最新更新