如何使用 ref 操作 DOM?(二)使用示例

1,177 阅读2分钟

这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

翻译自:beta.reactjs.org/learn/manip…

因为 React 已经根据 render 的输出处理了 DOM 结构,所以你的组件不经常需要操作 DOM。然而,有的时候你可能需要操作 React 管理的 DOM 元素,比如,将焦点放到一个节点上,滚动到这个节点,或者去计算它的宽和高。React 中没有内置的方法去做这些事情,所以你将会需要 ref 去指向这个 DOM 节点。

这个系列的文章你将会学到:

  • 如何使用 ref 属性访问由 React 管理的 DOM 节点
  • 如何将 JSX 的 ref 属性关联到 useRef 钩子
  • 如何访问其他组件的 DOM 节点
  • 在哪种情况下,修改 React 管理的 DOM 是安全的

关于 ref 相关的介绍和例子,可以看我前面一个系列的文章 useRef 简单易懂解析

系列文章

如何使用 ref 操作 DOM?(一)使用 ref 访问 DOM 节点

示例:input 聚焦

在本例中,单击按钮将聚焦 input:

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

要实现这一点:

  • useRef 钩子声明 inputRef
  • inputRef 作为 <input ref={inputRef}> 传递。这告诉 React 将这个 <input> 的 DOM 节点放入 inputRef.current 中。
  • handleClick 函数中,从 inputRef.current 读取 input 的 DOM 节点,并使用 inputRef.current.focus() 对其调用 focus()
  • 使用 onClickhandleClick 事件处理程序传递给 <button>

虽然 DOM 操作是 refs 最常见的用例,但 useRef Hook 可以用于在 React 之外存储其他东西,比如计时器 id。与 state 类似,refs 在呈现之间保持不变。您甚至可以将 refs 视为状态变量,当您设置它们时,它们不会触发重新 render

示例:滚动到一个元素

一个组件中可以有多个引用。在这个例子中,有一个由三个图像和三个按钮组成的轮播,通过调用浏览器 scrollIntoView() 方法在相应的 DOM 节点上将它们居中显示在视口中:

import { useRef } from 'react';

export default function CatFriends() {
  const firstCatRef = useRef(null);
  const secondCatRef = useRef(null);
  const thirdCatRef = useRef(null);

  function handleScrollToFirstCat() {
    firstCatRef.current.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    });
  }

  function handleScrollToSecondCat() {
    secondCatRef.current.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    });
  }

  function handleScrollToThirdCat() {
    thirdCatRef.current.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    });
  }

  return (
    <>
      <nav>
        <button onClick={handleScrollToFirstCat}>
          Tom
        </button>
        <button onClick={handleScrollToSecondCat}>
          Maru
        </button>
        <button onClick={handleScrollToThirdCat}>
          Jellylorum
        </button>
      </nav>
      <div>
        <ul>
          <li>
            <img
              src="https://placekitten.com/g/200/200"
              alt="Tom"
              ref={firstCatRef}
            />
          </li>
          <li>
            <img
              src="https://placekitten.com/g/300/200"
              alt="Maru"
              ref={secondCatRef}
            />
          </li>
          <li>
            <img
              src="https://placekitten.com/g/250/200"
              alt="Jellylorum"
              ref={thirdCatRef}
            />
          </li>
        </ul>
      </div>
    </>
  );
}