# React Hooks useRef 使用范围
React Class组件中的createRef
,与React Hooks函数组件中的useRef
相对应。在说useRef之前,就不得不先看下createRef
这个API的目的,它是为了解决什么问题?这样我们才能更加的了解 useRef
API。
# 了解 createRef API
React.createRef 可以很好的帮助开发者,获取到DOM元素节点实例,也可以帮助我们获取Class组件的组件实例。对于 createRef
API 适用情况,在官方文档中已有给出:
下面是几个适合使用 refs 的情况:
- 管理焦点,文本选择或媒体播放。
- 触发强制动画。
- 集成第三方 DOM 库。
避免使用 refs 来做任何可以通过声明式实现来完成的事情。
// 通过创建createRef,控制input元素节点DOM
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 创建一个 ref 来存储 textInput 的 DOM 元素
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// 直接使用原生 API 使 text 输入框获得焦点
// 注意:我们通过 "current" 来访问 DOM 节点
this.textInput.current.focus();
}
render() {
// 告诉 React 我们想把 <input> ref 关联到
// 构造器里创建的 `textInput` 上
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
// 通过创建createRef,控制子class组件this实例
class AutoFocusTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focusTextInput();
}
render() {
return (
{ /* CustomTextInput 必须是class组件才有效 */ }
<CustomTextInput ref={this.textInput} />
);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
以上就是 createRef
API 的典型使用方法,不过有点需要注意,通过React.createRef
创建的实例,不能挂在函数组件上,因为它们没有实例。如果一定要使用,可以通过props参数的形式进行传递。
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# useRef 使用
useRef
的主要功能与createRef
类似,通过声明 useRef
变量而后赋值访问DOM节点。不过相对于createRef
,useRef
功能更加全面和多样。
# 访问DOM节点
function TextInputWithFocusButton() {
const inputEl = useRef(null);
// `current` 指向已挂载到 DOM 上的文本输入元素
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
通过ref绑定访问DOM节点,DOM节点依然是挂载在current上。这依然是它的核心功能;
# 保存任何可变值
function Timer() {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
// ...
});
intervalRef.current = id;
return () => {
clearInterval(intervalRef.current);
};
});
function handleCancelClick() {
clearInterval(intervalRef.current);
}
return (
// ...
)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
useRef
对象是一个 current 属性可变且可以容纳任意值的通用容器。请记住,当 ref 对象内容发生变化时,useRef 并_不会_通知,而且每次渲染时都会返回同一个 ref 对象。
# ref 回调
function MeasureExample() {
const [height, setHeight] = useState(0);
const measuredRef = useCallback(node => {
if (node !== null) {
setHeight(node.getBoundingClientRect().height);
}
}, []);
return (
<>
<h1 ref={measuredRef}>Hello, world</h1>
<h2>The above header is {Math.round(height)}px tall</h2>
</>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
通过useCallback
传递依赖为 []
,保证当且仅当组件挂载和卸载时,callback ref 才会被调用。
我们没有选择使用 useRef,因为当 ref 是一个对象时它并不会把当前 ref 的值的 变化 通知到我们。使用 callback ref 可以确保 即便子组件延迟显示被测量的节点 (比如为了响应一次点击),我们依然能够在父组件接收到相关的信息,以便更新测量结果。
createRef
和 useRef
存在明显的差异,不过主体功能基本一致,useRef
不止可访问DOM阶段,还可以在 current 属性存储任意变量而不会被渲染修改,ref 回调没有大的变化,依然是通过传入函数,是 ref 功能扩大化,可以做更多的事情。
男性,武汉工作,会点Web,擅长Javascript.
技术或工作问题交流,可联系微信:1169170165.