Ref转发是一项将ref自动地通过组件传递到其一子组件的技巧(允许某些组件接收ref,并将其向下传递给子组件).
对一些高可复用的“叶”组件,倾向于在整个应用中以一种常规DOM button和input的方式被使用,并且访问其DOM节点,对焦点的管理、选中或动画来说是不可避免的。
FunctionButton使用React.forwardRef来获取传递给它的ref,然后转发到它渲染的DOM Button,
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref}>{props.children}</button>
))
// 你可以直接获取DOM button的ref
const ref = React.createRef();
<FancyButton ref={ref}>click me</FancyButton>
实现过程
- 我们通过调用
React.createRef创建了一个 React ref 并将其赋值给 ref 变量。 - 我们通过指定 ref 为 JSX 属性,将其向下传递给 。
- React 传递 ref 给 forwardRef 内函数 (props, ref) => ...,作为其第二个参数。
- 我们向下转发该 ref 参数到
<button ref={ref}>,将其指定为 JSX 属性。 - 当 ref 挂载完成,ref.current 将指向
<button>DOM 节点
第二个参数只在使用React.forwardRef定义组件时存在,常规函数和class组件不接收ref参数,且props中也不存在ref
在高阶组件中转发
在高阶组件上定义ref, refs是不会传递下去的,这是因为ref不是props属性,就像key一样,其被React做了特殊处理,对HOC添加ref,该ref将引用最外层容器组件,而不是被包裹的组件。
const hoc = WrapperComponent => React.forwardRef((props, ref) => {
return <WrapperComponent {...props} countryRef={ref} />
})
function Country({label, countryRef}) {
return (
<div>
<label>{label}</label>
<input ref={countryRef}/>
</div>
)
}
// 使用
const HocCountry = hoc(Country);
<HocCountry ref={this.countryRef} />
还可以和context一起使用
<!--GGEditor中的一段代码-->
import React from 'react';
import { Graph } from '@/common/interface';
const EditorContext = React.createContext({});
export const withEditorContext = function(WrappedComponent) {
const InjectEditorContext = props => {
const { forwardRef, ...rest } = props;
return (
<EditorContext.Consumer>
{context => <WrappedComponent ref={forwardRef} {...rest} {...context} />}
</EditorContext.Consumer>
);
};
return React.forwardRef((props, ref) => (
<InjectEditorContext forwardRef={ref} {...props} />
));
};
export default EditorContext;