React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

这个特殊的属性允许你引用 render() 返回的相应的实例

使用方法

绑定一个 ref 属性到 render 的返回值上:

<input ref="myInput" />

通过 this.refs 获取支撑实例:

1
2
3
var input = this.refs.myInput;
var inputValue = input.value;
var inputRect = input.getBoundingClientRect();

Hooks 出现后,Ref 有了一点变化:它可以引用任意值(Dom NodeJavaScript Value)

完整的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Counter() {
const hasClickedButton = React.useRef(false);

const [count, setCount] = React.useState(0);

function onClick() {
const newCount = count + 1;
setCount(newCount);
hasClickedButton.current = true;
}

console.log('Has clicked button? ' + hasClickedButton.current);

return (
<div>
<p>{count}</p>

<button type="button" onClick={onClick}>
Add
</button>
</div>
);
}

const hasClickedButton = React.useRef(false);

DOM REFS

1
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
function App() {
return (
<ComponentWithDomApi
label="Label"
value="Value"
isFocus
/>
);
}

function ComponentWithDomApi({ label, value, isFocus }) {
const ref = React.useRef(); // (1)

React.useEffect(() => {
if (isFocus) {
ref.current.focus(); // (3)
}
}, [isFocus]);

return (
<label>
{/* (2) */}
{label}: <input type="text" value={value} ref={ref} />
</label>
);
}
  • (1) 创建了一个Ref对象且没有赋初始值
  • (2) 通过指定input的ref属性与创建的Ref对象关联
  • (3) ref.current.focus() 使用input的API

看一个监听文本变化后改变页面标题的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function ComponentWithRefRead() {
const [text, setText] = React.useState('Some text ...');

function handleOnChange(event) {
setText(event.target.value);
}

const ref = React.useRef();

React.useEffect(() => {
const { width } = ref.current.getBoundingClientRect();

document.title = `Width:${width}`;
}, [text]);

return (
<div>
<input type="text" value={text} onChange={handleOnChange} />
<div>
<span ref={ref}>{text}</span>
</div>
</div>
);
}

这个例子也可以采用callback ref实现。

既不需要 useEffect 也不需要 useRef , 因为每次 re-render 都会执行 callback ref函数,回调函数会传入绑定的 DOM 节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function ComponentWithRefRead() {
const [text, setText] = React.useState('Some text ...');

function handleOnChange(event) {
setText(event.target.value);
}

const ref = (node) => {
if (!node) return;

const { width } = node.getBoundingClientRect();

document.title = `Width:${width}`;
};

return (
<div>
<input type="text" value={text} onChange={handleOnChange} />
<div>
<span ref={ref}>{text}</span>
</div>
</div>
);
}