I'm trying to learn how forwardRef works in React and playing around with it based on official docs. I understand how it works with this basic example:
import { forwardRef, useRef, useImperativeHandle } from "react"
const ChildComp = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
showAlert() {
alert("Hello from Child Component")
},
}))
return <div></div>
})
function App() {
const childCompRef = useRef()
return (
<div>
<button onClick={() => childCompRef.current.showAlert()}>Click Me</button>
<ChildComp ref={childCompRef} />
</div>
)
}
export default App
When I click the button in App, it shows the alert, so far so good.
However based on my real use case, I have to do bunch of wrappings on top of my ChildComp, which could be simplified as the following. Here is the Codesandbox link
const getWrapper = () => {
return class Test extends Component{
public render() {
return this.props.children;
}
}
}
const withWrapper = (
Component: React.FunctionComponent | React.ForwardRefExoticComponent<React.RefAttributes<unknown>>
) => {
function Wrapped(props: any) {
return React.createElement(getWrapper(), {}, <Component {...props} />)
}
return Wrapped;
}
const ChildComp = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
showAlert() {
alert("Hello from Child Component!~")
},
}))
return <div></div>
})
const WrappedChild = withWrapper(ChildComp);
function App() {
const childCompRef = useRef()
return (
<div>
<button onClick={() => childCompRef.current.showAlert()}>Click Me</button>
<WrappedChild ref={childCompRef} />
</div>
)
}
It shows childCompRef.current is undefined when I click on the button. The wrappers cannot be removed due to legacy reasons. I'm wondering where in the process does it lose the "ref" and how could I make it work as before in this case? Do I need to wrap forwardRef somewhere else?
You need another layer of
forwardRef: