这是我参与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 简单易懂解析
系列文章
- 如何使用 ref 操作 DOM?(一)使用 ref 访问 DOM 节点
- 如何使用 ref 操作 DOM?(二)使用示例
- 如何使用 ref 操作 DOM?(三)如何使用 ref 回调去管理列表的 ref
- 如何使用 ref 操作 DOM?(四)forwardRef 访问自己组件的 DOM 节点
- 如何使用 ref 操作 DOM?(五)原理、react state 同步更新 DOM 的方式
- 如何使用 ref 操作 DOM?(六)最佳实践
总结
- 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?"
/>
);
}
);