3

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>
        </>
    );
}
2
  • 2
    full component code please. Commented Dec 8, 2020 at 15:08
  • 1
    @b3hr4d I posted the code for the full component! If you need any further detail I'll be more than happy to provide! Commented Dec 8, 2020 at 15:28

1 Answer 1

3

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>

Sign up to request clarification or add additional context in comments.

9 Comments

Thank you for your answer! I already tried this way and it make complete sense, but for some reason it doesn't work in my code. I posted the full component code, maybe you'll find what's wrong before I do :D
I understand the problem now but I didn't understand your solution, could you please refactor the first solution you gave me? I'm fairly new to React and I'm pretty confused at the moment
It works now! I just have to understand what you did and how you did it! Thank you so much for your patience!
@Zakaria Your welcome, I love helping people.
its because how ref props works in react , like mouseEvent have logic behind it. read this for more : reactjs.org/docs/refs-and-the-dom.html
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.