React之Refs

Refs是什么

引用官方的话:
Refs 提供了一种访问在 render 方法中创建的 DOM 节点或 React 元素的方式。

为什么需要Refs

在常规的 React 数据流中,props 是父组件与子组件交互的唯一方式。要修改子元素,你需要用新的 props 去重新渲染子元素。然而,在少数情况下,你需要在常规数据流外强制修改子元素。被修改的子元素可以是 React 组件实例,或者是一个 DOM 元素。在这种情况下,React 提供了解决办法。

用例

第一种用法

String 类型的 Refs

这种使用方法是老版本的用法,当然在16.4.1更新后,明确说了该种方法的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
27
28
29
30
class App extends Component{
constructor(props){
super(props);
this.state = {
value:""
};
}

componentDidMount() {
this.refs.myinput.focus();
}

render(){
var str = {
"width":220,
"textAlign":"center",
"margin":"auto"
}
return (
<div style={str}>
<input type="text" ref="myinput" />
</div>
)
}
}

ReactDOM.render(
<App />,
document.getElementById('root')
)

这个例子,当在第一次渲染后,input将会获得焦点。

第二种用法

下面我们改写下例子,来介绍第二种用法:创建 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Child extends Component {
constructor(props) {
super(props);
this.state = {
text: '我是初始值'
};
}
subHandleClick(){
this.setState({text: '我被父组件调用了,改变了内容!'})
}
render(){
return(
<div>
{this.state.text}
</div>
)
}
}

class Parent extends Component {
constructor(props) {
super(props);
this.test = React.createRef();
}

handleClick(){
console.log(this.test.current);
this.test.current.subHandleClick();
}

render(){
return(
<div>
<input
type="button"
value="父组件调用子组件方法"
onClick={this.handleClick.bind(this)}
/>
<Child ref={this.test} />
</div>
)
}
}

ReactDOM.render(
<Parent/>,
document.getElementById('root')
);

这里说明一下refs值得类型:
首先ref的值取决于节点的类型:

  • 当 ref 属性被用于一个普通的 HTML 元素时,React.createRef() 将接收底层 DOM 元素作为它的 current 属性以创建 ref
  • 当 ref 属性被用于一个自定义类组件时,ref 对象将接收该组件已挂载的实例作为它的 current 。
  • 你不能在函数式组件上使用 ref 属性,因为它们没有实例。

第三种用法

第三种:回调函数用法

  • React 也支持另一种设置 ref 的方式,称为“回调 ref”,更加细致地控制何时 ref 被设置和解除。
  • 不同于传递 createRef() 创建的 ref 属性,你会传递一个函数。这个函数接受 React 组件的实例或 HTML 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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class CustomTextInput extends React.Component {
constructor(props) {
super(props);

this.textInput = null;

this.setTextInputRef = element => {
this.textInput = element;
};

this.focusTextInput = () => {
// 直接使用原生 API 使 text 输入框获得焦点
if (this.textInput) this.textInput.focus();
};
}

componentDidMount() {
// 渲染后文本框自动获得焦点
this.focusTextInput();
}

render() {
// 使用 `ref` 的回调将 text 输入框的 DOM 节点存储到 React
// 实例上(比如 this.textInput)
return (
<div>
<input
type="text"
ref={this.setTextInputRef}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
ReactDOM.render(
<CustomTextInput/>,
document.getElementById('root')
)
Do the best!