通过深入了解视频聊天应用程序的底层原理来学习 React Hooks
像我认识的大多数开发人员一样,我每天在工作中都能学到很多东西。这也是我希望把编程融入到我的工作中的原因之一!
我真的很喜欢能立即应用新知识,这也有助于我更好地学习。尽管阅读了很多解释性文章和一些教程,但我直到需要深入研究Daily React 视频聊天演示时,才真正开始理解 React Hooks 。
当我思考视频聊天应用程序中的各种角色时(useEffect我们很多人每天都会使用这类应用程序),我更应该记住每个钩子是如何工作的,并认识到使用它们的其他机会。useMemouseCallback
如果您觉得阅读这篇关于实际应用的文章对您也有帮助,我决定写出来!在快速回顾一下 Hooks 之后,我们将通过 Daily演示应用程序来查看每个 Hooks 的示例,并解释我们为什么选择使用它们。
我在上一篇文章中提到过要避免使用全局变量,并且我正在努力改进,以便更好地分享同事们教给我的东西。这一轮的分享要感谢才华横溢的杰西·米切尔,我非常荣幸能与她共事并向她学习!
在我们被钩住之前
我非常喜欢Ali Spittel在最新一期Ladybug播客节目中对“钩子”的定义:
“Hooks 是一种特殊的函数,它允许你介入 React 组件的生命周期。因此,它们允许你执行普通函数无法执行的特殊操作。”
这意味着我们可以在组件挂载、更新和卸载时执行一些独特的操作。正如文档所述,我们可以利用状态和其他特性,而无需编写类组件。
考虑到以上概述,让我们来看看视频聊天应用程序中的三个 Hook useEffect:,useMemo,和useCallback。
useEffect管理状态中的参与者更新
有了它useEffect,我们就可以根据状态或属性的变化,在函数组件中执行副作用。
在视频聊天应用中,会发生很多事情!参与者会加入和退出通话,开启和关闭音频和视频,等等。我们的用户界面需要随着这些变化而更新。例如,当参与者加入或离开时,它需要自动添加和移除视频轨道。
Daily API会在这些事情发生时触发相应的事件,例如'participant-joined','track-stopped'等等。在我们的视频聊天应用中,我们会监听这些事件,它们的处理程序会particpantUpdated根据这些事件设置我们的状态。
这就是它的用武之地useEffect!我们只需要在发生更改时更新 UI,也就是participantUpdated设置好参数之后。我们将participantUpdated参数(以及包含更新后的参与者数据的调用对象)作为依赖项传递给一个useEffect钩子,这样我们就只在发生更改时更新参与者列表。
useEffect(() => {
if (participantUpdated) {
const list = Object.values(callObject?.participants());
setParticipants(list);
}
}, [participantUpdated, callObject]);
这就解决了存储参与者列表的问题,但是如何显示参与者信息、渲染他们的视频和音频轨道呢?这就需要我们下一个钩子了。
useMemo仅在必要时才重新渲染视频
useMemo返回一个经过记忆化处理的值。记忆化处理是指返回一个经过耗时函数调用后得到的值。
视频聊天应用中有很多耗时的计算。仅每个参与者的音频和视频轨道就包含大量数据,每次渲染都进行计算会耗费大量资源。
相反,我们将participants状态值作为依赖项传递给useMemo显示图块的钩子。
const displayLargeTiles = useMemo(() => {
const isLarge = true;
const tiles = participants?.filter((p) => !p.local);
return (
<div className="large-tiles">
{tiles?.map((t, i) => (
<Tile
key={`large-${i}`}
videoTrackState={t?.tracks?.video}
audioTrackState={t?.tracks?.audio}
isLarge={isLarge}
disableCornerMessage={isScreenShare}
onClick={
t.local
? null
: () => {
sendHello(t.id);
}
}
/>
))}
</div>
);
}
}, [participants]);
这个useMemo钩子允许我们只在视频发生变化时才更改显示的视频participants,而不是在每次渲染时都重新计算。
注意:由于我们构建的视频聊天应用参与者频繁变更,因此性能提升
useMemo非常显著;它节省了大量重新计算的时间。然而,在很多情况下,这个钩子可能超出了应用程序的实际需求。useMemo它经常被过度使用,所以请谨慎使用。
useCallbackstartLeavingCall()仅在必要时才重新渲染函数
就像useMemo防止我们重新计算未改变的值一样,useCallback它允许我们阻止特定函数重新渲染。
在我们的App.js 组件中,很多因素都可能触发重新渲染。但startLeavingCall例如,我们的函数只有在callObject存储调用数据的 `this` 或我们的 `this`appState发生变化时才需要重新渲染。这是因为该函数会根据这些值执行不同的操作。
我们传递callObject并appState作为我们的依赖项。
/**
* Starts leaving the current call.
*/
const startLeavingCall = useCallback(() => {
if (!callObject) return;
// If we're in the error state, we've already "left", so just clean up
if (appState === STATE_ERROR) {
callObject.destroy().then(() => {
setRoomUrl(null);
setCallObject(null);
setAppState(STATE_IDLE);
});
} else {
setAppState(STATE_LEAVING);
callObject.leave();
}
}, [callObject, appState]);
上瘾了还想看更多?
希望这篇文章能让大家对 Hooks 的实用性有更清晰的认识!你还能想到其他应用 Hooks 的新用法吗?useEffect欢迎在评论区留言!特别是如果你打算开发视频(或音频! )应用的话。你也可以在 Twitter上联系我!useMemouseCallback

