Home > OS >  React bootstrap hook onClick event function being struck-called by other event function
React bootstrap hook onClick event function being struck-called by other event function

Time:06-09

I'm try to putting an onClick event in a <Row> tag to triggering OffCanvas component when my state value is true. The issue is I cant close the canvas and I've found a weird behavior which I cant understand, it's seems like my first function for triggering the canvas always being called right after my close canvas function.

Here is my code sample:

import React, {useState} from 'react'
import "./index.scss"
import {Row, Col} from 'react-bootstrap';
import InspectSideDrawer from './InspectSideDrawer';

function InspectTransactionCard() {

    const [inspectCanvasShow, setInspectCanvasShow] = useState(false);
    
    const showCanvas = () => {
        console.log("Activating showCanvas...")
        setInspectCanvasShow(true);
    }    

    const closeInspectCanvas = (str) => {  
        console.log("Triggering close canvas...")
        setInspectCanvasShow(false)
        console.log("Triggering close canvas done")
    }    
    
    console.log("Currently canvas shows status is: " , inspectCanvasShow)


  return (
    <Row 
        className="mx-0 my-3 p-3 cst-inspect-transaction-card"
        onClick={()=>showCanvas()}
    >
        <Col className="px-0 d-flex flex-column justify-content-between">
            <small>
                <h6 className="">#NAS9DU239</h6>
            </small>
            <small className="d-flex align-items-center text-secondary">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="gray" className="bi bi-calendar" viewBox="0 0 16 16">
                    <path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
                </svg>
                <span className="mx-1">10 May 2022</span>
            </small>
        </Col>
        <Col className="px-0 d-flex flex-column justify-content-between">
            <div className="text-end">
                <h6>Status:
                    <span className="cst-text-highlight-blue"> Checking</span>
                </h6>

            </div>
            <div className="text-end text-secondary">
                <small>Po No:
                    <span> 01229527071243248</span>
                </small>
            </div>
        </Col>

        <InspectSideDrawer
            inspectCanvasShow={inspectCanvasShow}
            closeInspectCanvas={closeInspectCanvas}
        />

    </Row>
  )
}

export default InspectTransactionCard;

And Here is my OffCanvas component:

import React from 'react'
import "./index.scss"
import {Row, Col, Offcanvas, Button} from 'react-bootstrap'

function InspectSideDrawer({inspectCanvasShow, closeInspectCanvas, setInspectCanvasShow}) {

  return (
    <Offcanvas className="cst-side-drawer" placement='end' show={inspectCanvasShow} onHide={closeInspectCanvas}>  
        <Offcanvas.Header closeButton>  
        <Offcanvas.Title>Inspection Detail</Offcanvas.Title>  
        </Offcanvas.Header>  
        <Offcanvas.Body>  
        </Offcanvas.Body>  
    </Offcanvas>  
  )
}

export default InspectSideDrawer;

For more further demonstration, I have provided a screenshot below:

first_screenshot As you can see in the first screenshot , the canvas status default value is 'false' and this is correct.

second_screenshot In second screenshot, I have trigger the showCanvas function and the canvas works normally as long as the canvas status, everything seems fine.

third_screenshot In third screenshot, I want to close the canvas by clicking the X button which will triggering closeInspectCanvas function. However, as you can see, the showCanvas function has being called back right after my closeInspectCanvas function, it cause my canvas status value back to true and the canvas cannot be closed, I have no idea in this part.

The thing I've encounter is, it's all work normally as I'm expected if I put the onClick event in <Button> tags, but not with other tags. Anyway, I have to achieve this kind of UI in my project and I need your help.

CodePudding user response:

After taking a look about bubbling concept, I understand that my code has a similar phenomenon. It was caused by a parent and child HTML structure, I have try to trigger a click event from the child, and what happen here is when the child event finished, it will continue to trigger it's parent event if there is one. Afterall, I have got two solutions for this issue:

First solution is to add event.stopPropagation() on the click handle to prevents other propagation event. However, my button click handle comes with the library and I was unable to passing the event as a parameter. Therefore, I cannot yet use this solution to fix my issue, at least for now.

Second solution is to split my component and wrap it with an extra fragment. So it won't cause bubbling and the event will not disturbed by other propagation. Here is the code example:

import React, {useState} from 'react'
import "./index.scss"
import {Row, Col} from 'react-bootstrap';
import InspectSideDrawer from './InspectSideDrawer';

function InspectTransactionCard() {

    const [inspectCanvasShow, setInspectCanvasShow] = useState(false);
    
    const showCanvas = () => {
        console.log("Activating showCanvas...")
        setInspectCanvasShow(true);
    }    

    const closeInspectCanvas = (e) => {  
        e.stopPropagation()
        console.log("Triggering close canvas...")
        setInspectCanvasShow(false)
        console.log("Triggering close canvas done")
    }    
    
    console.log("Currently canvas shows status is: " , inspectCanvasShow)


  return (
    <>  
        <Row 
            className="mx-0 my-3 p-3 cst-inspect-transaction-card"
            onClick={()=>showCanvas()}
        >
            <Col className="px-0 d-flex flex-column justify-content-between">
                <small>
                    <h6 className="">#NAS9DU239</h6>
                </small>
                <small className="d-flex align-items-center text-secondary">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="gray" className="bi bi-calendar" viewBox="0 0 16 16">
                        <path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
                    </svg>
                    <span className="mx-1">10 May 2022</span>
                </small>
            </Col>
            <Col className="px-0 d-flex flex-column justify-content-between">
                <div className="text-end">
                    <h6>Status:
                        <span className="cst-text-highlight-blue"> Checking</span>
                    </h6>

                </div>
                <div className="text-end text-secondary">
                    <small>Po No:
                        <span> 01229527071243248</span>
                    </small>
                </div>
            </Col>


        </Row>
        <InspectSideDrawer
            inspectCanvasShow={inspectCanvasShow}
            closeInspectCanvas={closeInspectCanvas}
        />
    </>
  )
}

export default InspectTransactionCard  

Thank you for you guys help.

CodePudding user response:

If the X button element is a child of the <Row />, the click event will bubble up and it will fire the listener that you added on <Row />. You can read more about bubbling here

What you can do to prevent it is add event.stopPropagation() in the click handler of the X button.

const handleClick= (event) => {
  event.stopPropagation()
  // rest of the code
}

<button onClick={handleClick}>X</button>
  • Related