How do you wrap a forwardRef component with a HOC?
Asked Answered
E

2

7

How do you go about wrapping a forwardRef component?

For example, in my Cell Editor:

import React, {useEffect, forwardRef, useImperativeHandle, useRef} from "react";

export default forwardRef((props, ref) => {
    const inputRef = useRef();
    const { someProp } = props;
    useImperativeHandle(ref, () => {
        return {
            getValue: () => {
                return inputRef.current.value;
            }
        };
    });
    return <input type="text" ref={inputRef} someProp={someProp}/>;
})

If I wanted to expose a variable (someProp) inside to a HOC, how would I go about doing that?

function someProps(WrappedComponent, someProp) {
    return (props) => <WrappedComponent {...props} someProp={someProp}/>
}

someProps(CellEditor, {propName: propValue});

Whenever I try to wrap a forwardedRef component, it looks like the ref isn't being recognized correctly

Ellanellard answered 8/7, 2020 at 21:28 Comment(0)
F
4

If you're returning a wrapped component, then you have to also forward its reference by using forwardRef() and setting the ref prop. Taking your example above:

function someProps(WrappedComponent, someProp) {
  return forwardRef((props, ref) => (
    <WrappedComponent {...props} ref={ref} someProp={someProp} />
  ));
}
Follmer answered 8/7, 2020 at 22:1 Comment(1)
When I try using forwardRef on a component, like Robin's example above, I get an error "function components cannot be given refs". What's the secret sauce to making this work? Newbie here.Grasp
G
3

Suppose below HOC:

function withErrorBoundary (Component) {
  return (props) => <ErrorBoundary><Component {...props} /></ErrorBoundary>
}

This is NOT usable with React.forwardRef:

const FooWithErrorBoundary = withErrorBoundary(React.forwardRef(Foo))

function Foo(props, ref) {
  // `ref` is `undefined` here (instead of `someRef`)!!!
}

function SomeComponent {
  const someRef = useRef()
  // ...
  return <Foo {...someProps} ref={someRef} />
}

But if we change the HOC implementation to this:

function withErrorBoundary (Component) {
  return React.forwardRef((props, ref) => <ErrorBoundary><Component {...props} ref={ref} /></ErrorBoundary>)
}

then it works with both:

withErrorBoundary(React.forwardRef(Foo)) // function Foo (props, ref) {...}

and:

withErrorBoundary(Bar) // function Bar (props) {...}

UPDATE:

Full TypeScript example:
export function withErrorBoundary<P extends object, R>(
  Component: ComponentType<P>,
) {
  return forwardRef<R, P>(function WithErrorBoundary(props, ref) {
    return (
      <ErrorBoundary>
        <Component {...props} ref={ref} />
      </ErrorBoundary>
    )
  })
}
Gandhiism answered 30/1, 2023 at 22:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.