-
ref 用在class组件上是对组件实例的引用,用在dom元素上是对该元素真实dom节点的引用,得到引用以后就可以调用组件内定义的函数或操作dom节点(不能在函数式组件上使用 ref 属性,因为它们没有实例)。
-
可以通过 ReactDOM.findDOMNode(ref) 来获取组件或dom元素挂载后真实的dom节点(对于dom元素上使用ref的情况,ref本身引用的就是该元素真实的dom节点,所以无需使用 ReactDOM.findDOMNode(ref) 获取)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 1class Foo extends Component {
2 constructor(props) {
3 super(props);
4 this.refs = {
5 bar: null //对组件Bar实例的引用
6 }
7 }
8
9 componentDidMount() {
10 ReactDOM.findDOMNode(this.refs.bar); //ref引用组件对应的真实dom节点
11 }
12
13 render() {
14 return (
15 <div>
16 <Bar ref={bar => this.refs.bar = bar} />
17 </div>
18 )
19 }
20}
21
-
ref 属性获取的是真实dom节点,所以必须等到 vDom 挂载到文档后使用这个属性,否则会报错。
-
ref 属性的 3 种用法:
1)字符串(已弃用)
2)回调函数
3)React.createRef()
回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1// 1. dom节点上使用回调函数
2class MyTitle extends React.Component {
3 handleClick() {
4 this.textInput.focus();
5 }
6
7 render() {
8 return (
9 <div>
10 <input type="text" ref={(input) => { this.textInput = input; }} />
11 <input type="button" value="点我" onClick={this.handleClick.bind(this)} />
12 </div>
13 )
14 }
15}
16
1
2
3 1// 2. 类组件上使用回调函数
2<CustomInput ref={(input) => {this.customInput = input;}} />
3
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 1// 3. 跨级获取子孙级dom节点或组件实例
2function CustomTextInput(props) {
3 return (
4 <div>
5 <input ref={props.inputRef} />
6 </div>
7 );
8}
9function Parent(props) {
10 return (
11 <div>
12 My input: <CustomTextInput inputRef={props.inputRef} />
13 </div>
14 );
15}
16class Grandparent extends React.Component {
17 render() {
18 return (
19 <Parent
20 inputRef={el => this.inputElement = el}
21 \/>
22 );
23 }
24}
25
回调函数的触发时机:
1. 组件渲染后,即渲染后,componentDidMount之前
2. 组件卸载后,即componentWillUnmount后,此时,入参为null
3. ref 改变后
React.createRef()
-
在 React16.3 之后,可以使用 React.createRef() 创建 Ref 对象,ref.current 属性将能拿到真实的 dom 节点或组件实例。
-
用 createRef 创建 Ref,并触发获取到的组件实例内部的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 1class Foo extends React.Component {
2 constructor(props) {
3 super(props)
4 this.myRef = React.createRef();
5 }
6
7 handleClick = () => {
8 this.myRef.current.handleClick();
9 }
10
11 render() {
12 return (
13 <div>
14 <Wrap ref={this.myRef} />
15 <button onClick={this.handleClick}>触发Wrap组件内部的handleClick方法</button>
16 </div>
17 )
18 }
19}
20
- React.forwardRef()
同样是 React16.3 之后提供的,用来创建子组件,以传递ref,实现跨级获取子孙级dom节点或组件实例的功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 1//子组件(通过forwardRef方法创建)
2const Child=React.forwardRef((props,ref)=>(
3 <input ref={ref} />
4));
5
6//父组件
7class Father extends React.Component{
8 constructor(props){
9 super(props);
10 this.myRef=React.createRef();
11 }
12 componentDidMount(){
13 console.log(this.myRef.current);
14 }
15 render(){
16 return <Child ref={this.myRef}/>
17 }
18}
19
解析:父组件的使用方法没有改变,只是子组件用 forwardRef 方式创建。正常情况下,子组件上 ref 属性是对子组件实例的引用,子组件用 forwardRef 方式创建以后,更改了子组件上 ref 的引用,指向了子组件内部指定的 dom 元素或组件实例。所以父组件在操作 ref 的时候,就是在操作子组件内的 dom 元素或组件实例。
forwardRef 在高阶组件中可以获取到原始组件的实例。
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 1//生成高阶组件
2const LogProps=logProps(Child);
3
4//调用高阶组件
5class Father extends React.Component{
6 constructor(props){
7 super(props);
8 this.myRef=React.createRef();
9 }
10 componentDidMount(){
11 console.log(this.myRef.current);
12 }
13 render(){
14 return <LogProps ref={this.myRef}/>
15 }
16}
17
18//HOC
19function logProps(Component) {
20 class LogProps extends React.Component {
21 componentDidUpdate(prevProps) {
22 console.log('old props:', prevProps);
23 console.log('new props:', this.props);
24 }
25
26 render() {
27 const {forwardedRef, ...rest} = this.props;
28
29 // Assign the custom prop "forwardedRef" as a ref
30 return <Component ref={forwardedRef} {...rest} />;
31 }
32 }
33
34 // Note the second param "ref" provided by React.forwardRef.
35 // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
36 // And it can then be attached to the Component.
37 return React.forwardRef((props, ref) => {
38 return <LogProps {...props} forwardedRef={ref} />;
39 });
40}
41
总结:要改变哪个组件上 ref 的指向,哪个组件就用 forwardRef 创建。