Search code examples
reactjsreact-hooksuse-ref

ReactJs: Why ref.current returns null when the component is rendered?


I have a button inside a cart and I want give it an animation whenever the cart is opened. To target it I used useRef and tried to log in the console the result:

const checkoutBtnRef = useRef("null");

    useEffect(() => {
        console.log(checkoutBtnRef.current);
    }, [cartOpen]);

The problem is that current is null when I open the cart and returns the actual button only when I close the cart, I expected it to be the opposite. Any idea?

FULL COMPONENT CODE

export default function TopNav() {
    const classes = useStyles();
    const [cartOpen, setCartOpen] = useState(false);
    const checkoutBtnRef = useRef("null");

    useEffect(() => {
        console.log(checkoutBtnRef.current);
    }, [cartOpen]);

    return (
        <>
            <Container maxWidth="xl">
                <div className={classes.root}>
                    <CardMedia
                        image="https://www.example.com"
                        className={classes.media}
                    />
                    <SearchBar placeholder="Search" className={classes.searchBar} />
                    <div className={classes.iconsContainer}>
                        <PersonIcon className={classes.icon} />
                        <FavoriteBorderIcon className={classes.icon} />
                        <Badge
                            invisible={false}
                            variant="dot"
                            color="error"
                            onClick={() => setCartOpen(true)}
                        >
                            <ShoppingBasketIcon className={classes.icon} />
                        </Badge>
                    </div>
                </div>
            </Container>
            <Drawer
                classes={{
                    paper: classes.cart,
                }}
                anchor="right"
                open={cartOpen}
                transitionDuration={{ enter: 500, exit: 200 }}
                onClose={() => setCartOpen(false)}
            >
                <div className={classes.topCartContent}>
                    <Typography variant="h5">Cart</Typography>
                    <CloseIcon
                        className={classes.closeIcon}
                        onClick={() => setCartOpen(false)}
                    />
                </div>
                <Divider />
                <List>
                    <CartItem />
                </List>
                <Button
                    classes={{
                        root: classes.checkoutBtn,
                    }}
                    variant="outlined"
                    onClick={() => setCartOpen(false)}
                    ref={checkoutBtnRef}
                >
                    checkout
                </Button>
            </Drawer>
        </>
    );
}

Solution

  • EDIT : your drawer has delay and your button didn't render yet so u cant see button on cartOpen change event and ...

    so use this for storing and call your functions instead of useEffect.

     const checkoutBtnRef = (ref) => {
       console.log(ref);
       if (ref){
          // do ur staff here
       }
     };
    

    If u need useEffect u can do it like this :

      const [btnRef, setBtnRef] = useState(null);
    
      const checkoutBtnRef = (ref) => {
        if (ref) setBtnRef(ref);
      };
    
      useEffect(() => {
        console.log(btnRef);
      }, [btnRef]);
    

    Old answer:

    const App = ()=>{
      const [cart,setCart]= React.useState(false);
      const [btnRef, setBtnRef] = React.useState(null);
    
      const checkoutBtnRef = (ref) => {
        if (ref) setBtnRef(ref);
        else setBtnRef(null)
      };
    
      React.useEffect(() => {
        console.log(btnRef);
      }, [btnRef]);
      
      const cartHandler = () => {
        setTimeout(()=>{
           setCart((prev) => !prev)
        },1000);
      };
     return (
      <React.Fragment>
        <button onClick={cartHandler}>
         Cart
        </button>
        {cart && <button ref={checkoutBtnRef}>Check Out</button>}
       </React.Fragment>
     )
    }
    
    ReactDOM.render(
      <App />,
      document.getElementById("react")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="react"></div>