发布于 2026-01-06 5 阅读
0

通过深入了解视频聊天应用程序的底层原理来学习 React Hooks

通过深入了解视频聊天应用程序的底层原理来学习 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]);
Enter fullscreen mode Exit fullscreen mode

这就解决了存储参与者列表的问题,但是如何显示参与者信息、渲染他们的视频和音频轨道呢?这就需要我们下一个钩子了。

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]);
Enter fullscreen mode Exit fullscreen mode

这个useMemo钩子允许我们只在视频发生变化时才更改显示的视频participants,而不是在每次渲染时都重新计算。

注意:由于我们构建的视频聊天应用参与者频繁变更,因此性能提升useMemo非常显著;它节省了大量重新计算的时间。然而,在很多情况下,这个钩子可能超出了应用程序的实际需求。useMemo它经常被过度使用,所以请谨慎使用。

useCallbackstartLeavingCall()仅在必要时才重新渲染函数

就像useMemo防止我们重新计算未改变的值一样,useCallback它允许我们阻止特定函数重新渲染。

在我们的App.js 组件中,很多因素都可能触发重新渲染。但startLeavingCall例如,我们的函数只有在callObject存储调用数据的 `this` 或我们的 `this`appState发生变化时才需要重新渲染。这是因为该函数会根据这些值执行不同的操作。

我们传递callObjectappState作为我们的依赖项。

/**
   * 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]);
Enter fullscreen mode Exit fullscreen mode

上瘾了还想看更多?

电影《虎克船长》中的鲁菲奥

希望这篇文章能让大家对 Hooks 的实用性有更清晰的认识!你还能想到其他应用 Hooks 的新用法吗?useEffect欢迎在评论区留言!特别是如果你打算开发视频(或音频! )应用的话。你也可以在 Twitter上联系我useMemouseCallback

文章来源:https://dev.to/kimberleejohnson/learn-react-hooks-by-looking-under-the-hood-of-a-video-chat-app-3a5o