React-Bootstrap Offcanvas triggering my Navbar.Toggle to open and close my Navbar

  Kiến thức lập trình

I am developing a Navbar using React-Bootstrap that contains a cart-icon button that displays my Offcanvas as a minicart (a cart where you can add items to it throughout the website without having to go to the checkout cart to view your cart contents.)

My issue is that when I am toggling my offcanvas open and close it also triggers my navbar.toggle to open and close the (bottom-half) of my navbar. I have added console.logs to debug when the Navbar.Toggle is clicked and the logs are not fired when I open and close the Offcanvas yet it still acts as if the Navbar.Toggle is being clicked to open and close the (bottom-half) of my navbar. In my Navigation.jsx code (code will be provided) my Navbar has a className=”navbar-bottom-half”. If, in my Navigation.css file i add the style: .navbar-bottom-half{ transition: none; }, it solves my issue when i am viewing it on desktop screens. But, if i add that same css code in my media query for the mobile view it does not solve my issue. Plus I feel like that css code is kind of hacky and not the correct way to solve my problem. I have ran into several issues kind of like this while using react-bootstrap but I have always been able to solve it in a “non-hacky” manner. Any and all feedback is much appreciated. Thank you for taking your time to read and potentially solve my issue.

In my details of my problem i discussed the ways I tried to solve the problem above. I am going to present my code below here.

Navigation.jsx (parent component handling state. I have added several comments for clarity, as this component consists of several “reusable components”.)

import React, { useState, useEffect } from "react";
import { Navbar, Container, Row, Col, Button, Nav } from "react-bootstrap";
import Logo from "./Logo";
import SearchBar from "./SearchBar";
import UserActions from "./UserActions";
import MiniCart from "./MiniCart";
import AccountModal from "./AccountModal";
import NavItems from "./NavItems";
import StartOrderModal from "./StartOrderModal";
import "./css/Navigation.css";

export default function Navigation({
  popoverVisible,
  togglePopover,
  badgeCount,
}) {
  // State for account modal visibility
  const [accountModalVisible, setAccountModalVisible] = useState(false);
  const toggleAccountModal = () => setAccountModalVisible(!accountModalVisible);

  // State for minicart visibility
  const [minicartVisible, setMinicartVisible] = useState(false);
  const toggleMinicart = () => setMinicartVisible(!minicartVisible);

  // State for favorites
  const [favorites, setFavorites] = useState([]);

  // State for Start Order Modal visibility
  const [startOrderVisible, setStartOrderVisible] = useState(false);
  const toggleStartOrder = () => setStartOrderVisible(!startOrderVisible);

  // Load favorites from localStorage on component mount
  useEffect(() => {
    const storedFavorites = JSON.parse(localStorage.getItem("Favorites")) || [];
    setFavorites(storedFavorites);
  }, []);

  // Function to update favorites
  const handleUpdateFavorites = (newFavorites) => {
    setFavorites(newFavorites);
    localStorage.setItem("Favorites", JSON.stringify(newFavorites));
  };

  const handleNavbarToggleClick = () => {
    console.log("Navbar.Toggle clicked");
  };

  return (
    <Navbar expand="lg" className="hth-navbar flex-column">
      {/* Top half of the navbar */}
      <Container fluid className="navbar-top">
        <Row className="navbar-top-half align-items-center justify-content-between w-100">
          {/* Logo */}
          <Col
            xs={3}
            lg={2}
            className="d-flex align-items-center justify-content-start"
          >
            <Logo />
          </Col>

          {/* User Actions for Mobile */}
          <Col xs={6} className="d-flex d-lg-none justify-content-center">
            <UserActions
              popoverVisible={popoverVisible}
              togglePopover={togglePopover}
              badgeCount={badgeCount}
              toggleMinicart={toggleMinicart}
              toggleAccountModal={toggleAccountModal}
            />
          </Col>

          {/* Toggle for Mobile */}
          <Col xs={3} className="d-flex d-lg-none justify-content-end">
            <Navbar.Toggle
              aria-controls="navbar-nav"
              className="navbar-toggle"
              onClick={handleNavbarToggleClick}
            />
          </Col>

          {/* Search Bar for Desktop */}
          <Col lg={6} className="d-none d-lg-flex align-items-center">
            <SearchBar />
          </Col>

          {/* User Actions for Desktop */}
          <Col lg={4} className="d-none d-lg-flex justify-content-end">
            <UserActions
              popoverVisible={popoverVisible}
              togglePopover={togglePopover}
              badgeCount={badgeCount}
              toggleMinicart={toggleMinicart}
              toggleAccountModal={toggleAccountModal}
            />
          </Col>
        </Row>

        {/* Search Bar for Mobile */}
        <Row className="w-100 justify-content-center search-bar-row d-lg-none">
          <Col xs={12}>
            <SearchBar />
          </Col>
        </Row>
      </Container>

      {/* Bottom half of the navbar */}
      <Navbar.Collapse id="navbar-nav" className="navbar-bottom-half w-100">
        <Container fluid className="px-3 d-flex justify-content-center">
          <Row className="w-100 align-items-start navbar-bottom">
            {/* Nav Items */}
            <Col xs={12} className="d-flex flex-column align-items-start">
              <Nav className="justify-content-center nav-items">
                <NavItems
                  favorites={favorites}
                  onUpdate={handleUpdateFavorites}
                />
              </Nav>

              {/* Start Order Button */}
              <Button
                variant="outline-danger"
                className="btn-modal start-order-button"
                onClick={toggleStartOrder}
              >
                START ORDER
              </Button>
            </Col>
          </Row>
        </Container>
      </Navbar.Collapse>

      {/* MiniCart Offcanvas */}
      <MiniCart
        offcanvasVisible={minicartVisible}
        toggleOffcanvas={toggleMinicart}
      />

      {/* Account Modal */}
      <AccountModal
        accountModalVisible={accountModalVisible}
        toggleAccountModal={toggleAccountModal}
      />

      {/* Start Order Modal */}
      <StartOrderModal
        showStartOrder={startOrderVisible}
        handleStartOrderClose={toggleStartOrder}
      />
    </Navbar>
  );
}

Here is my MiniCart.jsx (component that contains the Offcanvas):

import React from "react";
import { Offcanvas, Button } from "react-bootstrap";

export default function MiniCart({ offcanvasVisible, toggleOffcanvas }) {
  console.log("MiniCart Component Rendered - Visible:", offcanvasVisible);

  // Log when the Offcanvas is shown
  const handleOffcanvasShow = () => {
    console.log("MiniCart - Opening");
  };

  // Log when the Offcanvas is hidden
  const handleOffcanvasHide = () => {
    console.log("MiniCart - Closing");
  };

  return (
    <Offcanvas
      show={offcanvasVisible}
      onHide={() => {
        handleOffcanvasHide();
        toggleOffcanvas();
      }}
      onShow={handleOffcanvasShow}
      placement="end"
    >
      <Offcanvas.Header closeButton>
        <Offcanvas.Title>Cart</Offcanvas.Title>
      </Offcanvas.Header>
      <Offcanvas.Body>
        <div className="d-flex justify-content-between">
          {/* temporary text for now */}
          <span className="price-text">Estimated subtotal:</span>
          <span className="price-amount">$0.00</span>
        </div>
        <hr />
        {/* Going to add accordion here for different categories of items. */}
        <div
          className="accordion mini-cart-accordion"
          id="accordionPanelsStayOpenExample"
        >
          <div className="accordion-item currentOrder-accordion-item">
            <h2
              className="accordion-header currentOrder-accordion-header"
              id="panelsStayOpen-headingOne"
            >
              <Button
                className="accordion-button currentOrder-btn"
                type="button"
                data-bs-toggle="collapse"
                data-bs-target="#panelsStayOpen-collapseOne"
                aria-expanded="true"
                aria-controls="panelsStayOpen-collapseOne"
              >
                Current Order
              </Button>
            </h2>
            <div
              id="panelsStayOpen-collapseOne"
              className="accordion-collapse collapse show"
              aria-labelledby="panelsStayOpen-headingOne"
            >
              {/* temporary text for now */}
              <div className="accordion-body currentOrder-accordion-body">
                Your cart is currently empty.
              </div>
            </div>
          </div>
          <div className="accordion-item openOrders-accordion-item">
            <h2
              className="accordion-header openOrders-accordion-header"
              id="panelsStayOpen-headingTwo"
            >
              <Button
                className="accordion-button openOrders-btn collapsed"
                type="button"
                data-bs-toggle="collapse"
                data-bs-target="#panelsStayOpen-collapseTwo"
                aria-expanded="false"
                aria-controls="panelsStayOpen-collapseTwo"
              >
                Open Orders
              </Button>
            </h2>
            <div
              id="panelsStayOpen-collapseTwo"
              className="accordion-collapse collapse"
              aria-labelledby="panelsStayOpen-headingTwo"
            >
              <div className="accordion-body openOrders-accordion-body">
                Open Orders Here
              </div>
            </div>
          </div>
        </div>
      </Offcanvas.Body>
      <div className="offcanvas-footer mini-cart-footer">
        <Button
          type="submit"
          variant="secondary"
          className="empty-btn"
          data-bs-dismiss="offcanvas"
        >
          Empty Cart
        </Button>
        <Button
          as="a"
          href="/checkout/checkout"
          variant="primary"
          className="view-cart-btn"
        >
          View Cart
        </Button>
      </div>
    </Offcanvas>
  );
}

Sorry folks I actually just solved my problem. I tried everything I could to not add state management on the Navbar.Collapse but that seems to be my only solution that is somewhat clean for this situation. Kind of odd as I was hoping react-bootstrap would manage this itself. But problem solved. Thank you for looking. Let me know if you know of a better solution. Thanks.

Your minicart is inside the navbar component which may be triggering event propogation from minicart to navbar.

You can try

    <Offcanvas
      show={offcanvasVisible}
      onHide={(e) => {
        e.stopPropagation();
        handleOffcanvasHide();
        toggleOffcanvas();
      }}
      onShow={(e) => {
        e.stopPropagation();
        handleOffcanvasShow();
      }}
      placement="end"
    >

Theme wordpress giá rẻ Theme wordpress giá rẻ Thiết kế website Kho Theme wordpress Kho Theme WP Theme WP

LEAVE A COMMENT