ARTICLE AD BOX
When adding the shown.bs.modal event on a bootstrap modal inside a useEffect in React it fires twice even if it only gets added once. So 'onshown' is logged twice while 'mount' is only logged once.
You can replicate it with the following code, to be clear strict mode is off and this is the only code in the React project.
React component:
import {useEffect, useRef} from "react"; export default function TestModal() { const modalRef = useRef(); useEffect(() => { console.log("mount"); const modelReference = modalRef.current; function onShown() { console.log("onshown") } if (modelReference) { console.log("add event listener"); modelReference.addEventListener("shown.bs.modal", onShown); } return () => { if (modelReference) { modelReference.removeEventListener("shown.bs.modal", onShown); } }; }, []); return ( <> <button data-bs-toggle="modal" data-bs-target={"#previewFileModal"} onClick={evt => { console.log("click"); }}> Open modal </button> <div ref={modalRef} className="modal fade" id={"previewFileModal"} tabIndex="-1" aria-labelledby={"previewFileModalLabel"} aria-hidden="true"> <div className="modal-dialog modal-fullscreen"> <div className="modal-content"> <div className="modal-header"> <h1 className="modal-title fs-5" id={"previewFileModalLabel"}>Preview</h1> <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div className="modal-body"> <div className={"text-center"}> </div> </div> <div className="modal-footer"> <button type="button" className="btn btn-secondary" data-bs-dismiss="modal">Close</button> </div> </div> </div> </div> </> ) }index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="" /> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css"> <title>Data Collection</title> </head> <body class="bg-light"> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script> </body> </html>When you take the same example and do it in a plain html file it works as expected and 'onshown' is only logged once.
html-sample:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous"> </head> <body> <button data-bs-toggle="modal" data-bs-target="#previewFileModal"> Open modal </button> <div class="modal fade" id="previewFileModal" tabIndex="-1" aria-labelledby="previewFileModalLabel" aria-hidden="true"> <div class="modal-dialog modal-fullscreen"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="previewFileModalLabel">Preview</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="text-center"> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> </div> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script> <script> const modal = document.getElementById('previewFileModal'); async function onShown() { console.log("onshown") } modal.addEventListener("shown.bs.modal", onShown); </script> </body> </html>