reactjstypescriptmaterial-uinavigation-drawerreact-forwardref

forwarded ref of material-ui component is always null


I'am currently working on a navbar with a drawer element from the material-ui libary.

I want to forward the <Drawer> Component to the parent navbar, which should let me call the toggleDrawer function of my NavDrawer component. I used the forwardRef function from the react libary but my ref ist always null.

The parent component

function ParentComponent() {
    const drawerRef = useRef<DrawerHandle>(null);
    
    const toggleDrawer = () => {
        //  drawerRef.current is null >:(
        drawerRef.current?.toggleDrawer(true)
    };

    return (
        <>
            <AppBar position={"sticky"}>
                <Button onClick={toggleDrawer} />     
            </AppBar>
            <NavigationDrawer open={false} ref={drawerRef}/>
        </>
    );
}

and the forwarded drawer component

import React, {forwardRef, useState} from 'react';
import {Drawer} from "@mui/material";

type Props = {
    open: boolean
};

export type DrawerHandle = {
    alterToggle: () => void
}

const NavigationDrawer = forwardRef<DrawerHandle, Props>((props, ref) => {

    const [isOpen, setIsOpen] = useState(props.open)

    const toggleDrawer =
        (open: boolean) =>
            (event: React.KeyboardEvent | React.MouseEvent) => {
                if (
                    event.type === 'keydown' &&
                    ((event as React.KeyboardEvent).key === 'Tab' ||
                        (event as React.KeyboardEvent).key === 'Shift')
                ) {
                    return;
                }
                setIsOpen(open)
            };

    return (
        <Drawer
            ref={ref}
            anchor={"left"}
            open={isOpen}
            onClose={toggleDrawer(false)}
        >
            <p>Item1</p>
            <p>Item2</p>
        </Drawer>
    );
})

I cant wrap my head around the issue here, maybe its type related but than the ref object should be an wrongly typed object but not null.


Solution

  • You don't have to pass ref to the Drawer since you don't need access to it's properties. All you need is just imperativeHandle to return the handler to the parent.

    // in NavDrawer
    
    useImperativeHandle(ref,
      () => ({
         toggleDrawer,
      }),
    []);
    

    Then the ref.current object in ParentComponent will contain toggleDrawer method.