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

React useRef Hook:不仅适用于 DOM 元素 修复:现在可以在 StarSearch 聊天正在进行时启动新的聊天 #3637

React useRef Hook:不仅适用于 DOM 元素

修复:现在可以在已有 StarSearch 聊天记录的情况下发起新的聊天 #3637

在这篇文章中,我们将介绍什么useRef是钩子,它的一些使用示例,以及何时不应该使用它。

useRef是什么?

该钩子会创建一个引用对象,该对象在其currentuseRef属性中存储一个可变值。该值可以是任何内容,从 DOM 元素到普通对象。与通过useState等钩子维护组件状态不同,通过该钩子修改引用对象不会触发组件的重新渲染,从而提升性能。useRef

示例

使用 useRef Hook 引用 DOM 元素

在 React 中,状态(state)管理着可能触发页面重新渲染的数据。但是,如果您需要一种直接访问文档对象模型(DOM)元素的方法,而这些元素又不应该导致页面重新渲染,该怎么办呢?这时就需要用到useRef hook 了。

通常情况下,你会这样做。

import { useEffect, useRef } from "react";

export const SomeComponent = () => {
  const firstNameInputRef = useRef<HTMLInputElement>(null);

  // for plain JavaScript change the above line to
  // const firstNameInputRef = useRef(null);

  useEffect(() => {
    firstNameInputRef.current?.focus();
  }, []);

  return (
    <form>
      <label>
        First Name:
        <input type="text" ref={firstNameInputRef}/>
      </label>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode
  1. 我们创建一个名为firstNameInputRefusing的变量useRef来引用 DOM 元素(初始值为 null),并使用该变量useEffect在初始渲染时聚焦输入元素。
  2. 在内部useEffect,我们检查输入框是否firstNameInputRef.current存在(初始渲染后它就是实际的 DOM 元素)。如果存在,我们就调用方法focus()将焦点设置到输入框上。

使用 useRef Hook 引用非 DOM 元素

最近,我一直在参与 Open Sauced 的StarSearch 项目,这是一个类似 Copilot for git history 的功能,我们已于 2024 年 5 月底发布。您可以在下面的博客文章中阅读更多关于 StarSearch 的信息。

请求内容是能够发起一个新的 StarSearch 对话。为此,我必须先停止当前的对话。如果您使用过OpenAI API 或类似的 API,它们通常会返回一个ReadableStream作为响应。

ReadableStream 是一种 Web API,它允许在数据可用时分块读取数据,从而能够高效地处理大型或实时数据集。在 API 响应的上下文中,这意味着我们可以立即开始处理数据,而无需等待整个响应完成。

我最初实现了这个功能,但如果响应开始以流的形式传输,就会出现问题。解决方案是通过钩子创建一个对可读流的引用useRef,并在开始新的对话时取消正在进行的对话。您可以在下面的拉取请求 (PR) 中看到这些更改。

修复:现在可以在已有 StarSearch 聊天记录的情况下发起新的聊天 #3637

描述

现在,新对话开始时的isRunning状态会重置false。这之前会导致在取消上一个对话并开始新对话时,无法启动新的对话流。

相关票务和文件

修复 #3636

手机和电脑屏幕截图/录制

CleanShot 2024-06-25 21:25:35

CleanShot 2024-06-25 21:26:04

质量保证步骤

  1. 前往任意工作区并打开 StarSearch
  2. 开始对话
  3. 点击 StarSearch 简洁标题栏中的“返回”按钮或“新建对话”按钮即可取消对话。
  4. 开始新的对话。
  5. 注意新加入的对话。

层级(工作人员将填补空缺)

  • [ ] 一级
  • [ ] 二级
  • [ ] 三级
  • [x] 第四层

[可选] 哪个 GIF 最能描述这条公关稿或者它带给你的感受?

所以现在,如果有人按下“创建新对话”按钮,我会取消 StarSearch 当前正在播放的响应,例如

  const streamRef = useRef<ReadableStreamDefaultReader<string>>();

  // for plain JavaScript change the above line to
  // const streamRef = useRef();  
...

  const onNewChat = () => {
    streamRef.current?.cancel();
    ...
  };

...

Enter fullscreen mode Exit fullscreen mode
  1. 我们创建一个名为streamRefusing的变量来保存对当前ReadableStreamDefaultReader 的useRef引用
  2. onNewChat函数检查是否streamRef.current存在(意味着流正在进行中)。
  3. 如果存在一个信息流,我们会在开始新的对话之前调用cancel()停止streamRef.current该信息流。

总结

useRef这完美地解决了我的使用场景。或许你会发现这个useRef钩子除了用于引用 DOM 元素之外,在其他方面也很有用。

你可以通过钩子将几乎任何内容存储在引用对象中useRef,这不会导致组件重新渲染。如果你要持久化组件状态,请选择useState其他钩子,例如 `setState` 或 `return`,useReducer这样组件才会重新渲染。

如需进一步了解useRefuseRef hook,我强烈建议查阅 React 文档

保持你的个性!

如果您想了解更多关于我在开源领域的工作,请在 OpenSauced 上关注我

文章来源:https://dev.to/opensauced/the-react-useref-hook-not-just-for-html-elements-3cf3