# 通过 ref 获取实例

# 类组件中

# 字符串形式

import React, { Component } from 'react';
export default class Demo extends Component {
	componentDidMount = () => {
		console.log(this.refs); // {currentDom: span}
	};

	render() {
		return <span ref="currentDom">span</span>;
	}
}

# 函数形式

import React, { Component } from 'react';
export default class Demo extends Component {
	componentDidMount = () => {
		console.log(this.currentDom); // span标签
	};

	render() {
		return <span ref={(node) => (this.currentDom = node)}>span</span>;
	}
}

# 对象形式

import React, { Component, createRef } from 'react';
export default class Demo extends Component {
	constructor(props) {
		super(props);
		this.currentDom = createRef(null);
	}
	componentDidMount = () => {
		console.log(this.currentDom); // {current: span}
	};

	render() {
		return <span ref={this.currentDom}>span</span>;
	}
}

# 函数组件中

在函数组件中我们可以通过 useRef 来获取 DOM 元素或组件的实例。

import React, { useEffect, useRef } from 'react';
export default function() {
	const currentDom = useRef(null);
	useEffect(() => {
		console.log(currentDom); // {current: span}
	});
	return <span ref={currentDom} />;
}

# ref高阶用法

# forwardRef转发ref

React.forwardRef (opens new window) 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。

# 跨层级获取

import React, { Component } from 'react';

function Son(props) {
	return <span ref={props.grandRef}>son</span>;
}

class Father extends Component {
	render() {
		console.log(this.props, this.props.ref); // props 是一个空对象 {}
		return <Son grandRef={this.props.ref} />;
	}
}

export default class GrandFather extends Component {
	constructor(props) {
		super(props);
	}
	componentDidMount = () => {
		console.log(this.node);
	};

	render() {
		return <Father ref={(node) => (this.node = node)} />;
	}
}

上面的代码我们想通过向下传递 ref 来获取 Son 组件中的内容,会报错:

我们可以使用 forwardRef 来实现这个需求:

import React, { Component, forwardRef } from 'react';

function Son(props) {
	return <span ref={props.grandRef}>son</span>;
}

class Father extends Component {
	render() {
		console.log(this.props); // this.props -> {grandRef: ƒ}
		return <Son grandRef={this.props.grandRef} />;
	}
}

const NewFather = forwardRef((props, ref) => <Father grandRef={ref} {...props} />);
export default class GrandFather extends Component {
	constructor(props) {
		super(props);
	}
	componentDidMount = () => {
		console.log(this.node); // span 标签
	};

	render() {
		return <NewFather ref={(node) => (this.node = node)} />;
	}
}

# 合并转发ref

import React, { Component, createRef, forwardRef } from 'react';
class Form extends Component {
  constructor(props) {
		super(props);
	}
  render() {
    return 'Form'
  }
}
class Home extends Component {
	constructor(props) {
		super(props);
    this.form = null;
    this.button = null;
	}
  componentDidMount = () => {
    // 可以改写父组件传递过来的 ref
    this.props.forwardRef.current = {
      form: this.form,
      button: this.button
    };
  };
  render() {
    return <>
      <button ref={button => this.button = button}>按钮</button>
      <Form ref={form => this.form = form}/>
    </>
  }
}
const ForwardRefHome = forwardRef((props, ref) => <Home forwardRef={ref} {...props}/>)
export default class Demo extends Component {
	constructor(props) {
		super(props);
		this.ref = createRef(null);
	}
  componentDidMount = () => {
    console.log(this.ref) // 输出修改后的ref
  };
  
	render() {
		return <ForwardRefHome ref={this.ref}/>;
	}
}

# 高阶组件转发

import React, { Component, forwardRef, useEffect, useRef } from 'react';

const HOC = (Component) => {
	class Wrap extends Component {
		constructor(props) {
			super(props);
		}
		render() {
			const { forwardRef, ...props } = this.props;
			return <Component ref={forwardRef} {...props} />;
		}
	}
  // 如果不这样写,ref 指向的就是高阶组件
	return forwardRef((props, ref) => <Wrap forwardRef={ref} {...props} />);
};
class Home extends Component {
	constructor(props) {
		super(props);
	}
	render() {
		return <span>home</span>;
	}
}
const HocHome = HOC(Home);
export default () => {
	const ref = useRef(null);
	useEffect(() => {
		console.log(ref);
	});
	return <HocHome ref={ref} />;
};

注意:

Function components cannot be given refs.