如何使用 ref 操作 DOM?(七)总结和实践

·  阅读 477

这是我参与11月更文挑战的第18天,活动详情查看: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 简单易懂解析

系列文章

总结

  • Refs 是一个通用概念,但大多数情况下您将使用它们来保存 DOM 元素。
  • 您通过传递 <div ref={myRef}> 指示 React 将 DOM 节点放入 myRef.current 中。
  • 通常,您将使用 refs 进行非破坏性操作,如聚焦、滚动或测量DOM元素。
  • 默认情况下,组件不会公开其 DOM 节点。您可以通过使用 forwardRef 并将第二个 ref 参数向下传递到特定节点来选择公开 DOM 节点。
  • 避免更改 React 管理的 DOM 节点。
  • 如果您确实修改了 React 管理的 DOM 节点,请修改 React 没有理由更新的部分。

实践

聚焦搜索字段

这样,点击“Search”按钮将焦点放在字段中。

export default function Page() {
  return (
    <>
      <nav>
        <button>Search</button>
      </nav>
      <input
        placeholder="Looking for something?"
      />
    </>
  );
}
复制代码

解决方案

向 input 添加一个 ref,并在 DOM 节点上调用 focus() 以使其聚焦:

import { useRef } from 'react';

export default function Page() {
  const inputRef = useRef(null);
  return (
    <>
      <nav>
        <button onClick={() => {
          inputRef.current.focus();
        }}>
          Search
        </button>
      </nav>
      <input
        ref={inputRef}
        placeholder="Looking for something?"
      />
    </>
  );
}
复制代码

上面的问题增加点难度~

实际开发中,我们通常不会把组件放到一个文件里,都会拆分开,那么在拆分开的时候如何传递 ref 呢?

使单击“Search”按钮将焦点置于该字段中。请注意,每个组件都定义在单独的文件中,不应将其移出。你如何将它们连接在一起?

// App.js
import SearchButton from './SearchButton.js';
import SearchInput from './SearchInput.js';

export default function Page() {
  return (
    <>
      <nav>
        <SearchButton />
      </nav>
      <SearchInput />
    </>
  );
}
复制代码
// SearchButton.js
export default function SearchButton() {
  return (
    <button>
      Search
    </button>
  );
}
复制代码
// SearchInput.js
export default function SearchInput() {
  return (
    <input
      placeholder="Looking for something?"
    />
  );
}
复制代码

解决方案

您需要向 SearchButton 添加一个 onClick,并让 SearchButton 将其向下传递到浏览器 <button>。您还将向下传递一个引用到 <SearchInput>,这将把它转发到真正的 <input> 并填充它。最后,在 click 处理程序中,将焦点调用在该引用中存储的 DOM 节点。

// App.js
import { useRef } from 'react';
import SearchButton from './SearchButton.js';
import SearchInput from './SearchInput.js';

export default function Page() {
  const inputRef = useRef(null);
  return (
    <>
      <nav>
        <SearchButton onClick={() => {
          inputRef.current.focus();
        }} />
      </nav>
      <!-- 这里 -->
      <SearchInput ref={inputRef} /> 
    </>
  );
}
复制代码
// SearchButton.js
export default function SearchButton({ onClick }) {
  return (
    <button onClick={onClick}>
      Search
    </button>
  );
}
复制代码
// SearchInput.js
import { forwardRef } from 'react';

export default forwardRef(
  // 使用 forwardRef 包裹组件,传递 ref
  function SearchInput(props, ref) {
    return (
      <input
        ref={ref}
        placeholder="Looking for something?"
      />
    );
  }
);
复制代码
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改