详解 React ref 属性

释放双眼,带上耳机,听听看~!
  1. ref 用在class组件上是对组件实例的引用,用在dom元素上是对该元素真实dom节点的引用,得到引用以后就可以调用组件内定义的函数或操作dom节点(不能在函数式组件上使用 ref 属性,因为它们没有实例)。

  2. 可以通过 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
  1. ref 属性获取的是真实dom节点,所以必须等到 vDom 挂载到文档后使用这个属性,否则会报错。

  2. 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()

  1. 在 React16.3 之后,可以使用 React.createRef() 创建 Ref 对象,ref.current 属性将能拿到真实的 dom 节点或组件实例。

  2. 用 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
  1. 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 创建。

 

 

给TA打赏
共{{data.count}}人
人已打赏
安全技术

RSA加密算法

2021-8-18 16:36:11

安全技术

C++ 高性能服务器网络框架设计细节

2022-1-11 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索