refs
- React v16.3后创建ref及使用可通过以下方式(注:不能在函数式组件上使用 ref 属性,因为它们没有实例)
class RefComponent extends React.Component {
render () {
return <div></div>
}
}
let myRef = React.createRef() // 通过React.createRef()方法创建ref
const handleClick = () => {
console.log(myRef.current) // 通过ref的current属性获取对应的组件或元素的实例
}
const Hello = (props) =>(
<>
<div onClick={handleClick}>0.0</div>
<RefComponent ref={myRef} > // 通过ref={MyRef}将组件或元素实例赋予ref
</RefComponent>
</>
)
- 可通过回调函数的方式去暴露子元素的ref
官网例子:
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}
- 假设我们现在有一个高阶组件ComponentA和利用这个ComponentA生成的一个ComponentB,当我们想尝试拿到ComponentB的实例时,如果我们直接给ComponentB加上之前提到的创建添加ref的方法,那么这里就会出现一个问题,最终我们获取到的实例是ComponentA的实例,而不是我们所需要的ComponentB的实例
const ContainerRef = (Component) => {
class Container extends React.Component {
render () {
return (
<div>
<Component {...this.props}/>
</div>
)
}
}
return Container
}
const Ref = (props) => <div>This is child</div>
const RefComponent = ContainerRef(Ref)
let myRef = React.createRef()
const handleClick = () => {
console.log(myRef)
}
const Hello = (props) =>(
<>
<button onClick={handleClick}>Test</button>
<RefComponent ref={myRef} > // 为myRef绑上ref实例
</RefComponent>
</>
)
效果如下,打印的ref实例是高阶组件的实例
为了解决这个问题,React为我们提供了一个React.forwardRef()方法,首先我们来看一下官方文档对这个方法的说明,“React.forwardRef accepts a render function that receives props and ref parameters and returns a React node”,这里只说了forwardRef接受一个有两个参数(props, ref)的render函数,没有它的具体原理,让我们先尝试官网的用法,结合下面的代码再来一探究竟
const ContainerRef = (Component) => {
class Container extends React.Component {
render () {
// 这里从props中获取出来forwardRef作为子组件的ref
const {forwardRef, ...rest} = this.props
return (
<div>
<Component {...rest} ref={forwardRef}/>
</div>)
}
}
// 传入上面提到的方法,forwardRef是React底层调用时传入的Ref,也是我们平常无法直接拿到的ref
// 一起放入props中,使Container可以从props中取出,传递给子组件
return React.forwardRef((props, forwardRef) => {
return (<Container {...props} forwardRef={forwardRef}/>)
})
}
class Ref extends React.Component {
render () {
return <div>This is child</div>
}
}
const RefComponent = ContainerRef(Ref)
let myRef = React.createRef()
const handleClick = () => {
//这里我们输出了上面React.forwardRef()返回的结果,是这样子的
// {$$typeof: Symbol(react.forward_ref), render: ƒ},得知React.forwardRef返回的是另一种React结点的实例,它类似于组件结点,但只有render方法,它的render函数就是我们传入的方法
console.log(RefComponent)
}
const Hello = (props) =>(
<>
<button onClick={handleClick}>Test</button>
<RefComponent ref={myRef} >
</RefComponent>
</>
)
总结:React.forwardRef方法返回一个类型为react.forward_ref的React结点实例,将我们传入的函数作为其实例的render方法,而该render方法被调用时,被传入其props和ref供我们使用,即可用来解决一个组件需要获取父组件赋予的ref的值。