在高阶组件中转发 refs
function logProps(WrappedComponent) { class LogProps extends React.Component { componentDidUpdate(prevProps) { console.log('old props:', prevProps); console.log('new props:', this.props); } render() { return <WrappedComponent {...this.props} />; } } return LogProps; }
“logProps” HOC 透传(pass through)所有 props
到其包裹的组件,所以渲染结果将是相同的。例如:我们可以使用该 HOC 记录所有传递到 “fancy button” 组件的 props:
1、假如不使用refs转发
class FancyButton extends React.Component { focus() { // ... } // ... } // 我们导出 LogProps,而不是 FancyButton。 // 虽然它也会渲染一个 FancyButton。 export default logProps(FancyButton);
下面的示例有一点需要注意:refs 将不会透传下去。这是因为 ref
不是 prop 属性。就像 key
一样,其被 React 进行了特殊处理。如果你对 HOC 添加 ref,该 ref 将引用最外层的容器组件,而不是被包裹的组件。
这意味着用于我们 FancyButton
组件的 refs 实际上将被挂载到 LogProps
组件:
import FancyButton from './FancyButton'; const ref = React.createRef(); // 我们导入的 FancyButton 组件是高阶组件(HOC)LogProps。 // 尽管渲染结果将是一样的, // 但我们的 ref 将指向 LogProps 而不是内部的 FancyButton 组件! // 这意味着我们不能调用例如 ref.current.focus() 这样的方法 <FancyButton label="Click Me" handleClick={handleClick} ref={ref} />;
2、使用请求转发
幸运的是,我们可以使用 React.forwardRef
API 明确地将 refs 转发到内部的 FancyButton
组件。React.forwardRef
接受一个渲染函数,其接收 props
和 ref
参数并返回一个 React 节点。例如:
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// 将自定义的 prop 属性 “forwardedRef” 定义为 ref
return <Component ref={forwardedRef} {...rest} />; }
}
// 注意 React.forwardRef 回调的第二个参数 “ref”。
// 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef”
// 然后它就可以被挂载到被 LogProps 包裹的子组件上。
return React.forwardRef((props, ref) => { return <LogProps {...props} forwardedRef={ref} />; });}