jjzjx118_2
jjzjx118_2

Reputation: 419

what is the right way to use forwardRef with withRouter

I just tried to use forwardRef with a withRouter(mycomponent) like this :

export default function App() {

  const childRef = useRef();
  const childWithRouteRef = useRef();

  useEffect(()=>{
    console.log("childWithRouteRef",childWithRouteRef);
    childRef.current.say();
    childWithRouteRef.current.say();
  })


  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <BrowserRouter>
      <Child ref={childRef}/>
      <ChildWithRoute_ ref={childWithRouteRef}/>
      </BrowserRouter>
    </div>
  );
}

const Child = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
        say: () => {
      console.log("hello")
        },
  }));

  return <div>Child</div>
})

const ChildWithRoute = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
        say: () => {
      console.log("hello")
        },
  }));

  return <div>ChildWithRoute</div>
})

const ChildWithRoute_ = withRouter(ChildWithRoute)

if I wrapped my component in a withRouter HOC, the ref will not working, it's always null. so how can I use forwardRef with a component wrapped in withRouter?

Upvotes: 3

Views: 2680

Answers (1)

Drew Reese
Drew Reese

Reputation: 202917

Forwarding refs in higher order components

... refs will not get passed through. That’s because ref is not a prop. Like key, it’s handled differently by React. If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component.

Looks as though the withRouter HOC doesn't yet forward refs. You can create your own little HOC to also forward a ref to the decorated-with-router component

const withRouterForwardRef = Component => {
  const WithRouter = withRouter(({ forwardedRef, ...props }) => (
    <Component ref={forwardedRef} {...props} />
  ));

  return forwardRef((props, ref) => (
    <WithRouter {...props} forwardedRef={ref} />
  ));
};

Usage:

const ChildWithRoute = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    say: () => console.log("hello from child with route"),
  }));

  return <div>ChildWithRoute</div>;
})

const ChildWithRouteAndRef = withRouterForwardRef(ChildWithRoute);

...
<ChildWithRouteAndRef ref={childWithRouteRef} />

Edit forwardRef - HOC

After a quick google search I found this issue, and based on the timestamps and last comment seems unlikely to be resolved. My above solution is similar to several approaches shared.

Upvotes: 4

Related Questions