I'm creating a Project where I fetch data from server & render 10
data in 10
different Bootstrap card using map()
. Each card have a button to popup a Modal. Beside I set a Link
to button that will show me route of that data.
react-bootstrap
for modal with hooks
react-router-dom
for show route
useState
hooks to set data from fetched data to modal.info_prop
& info
are different but it works with same data.import
all needed things & don't have any warning or error
useGetDataQuery()
using chapterId
.info
data & set to state with setInfo
info
setInfo
with handleModal
. I also try without this function. That time I do it on onClick
.Button
to show Modal
& Wrapped the button with Link
. Every Link
has a uniqe ID like 1:1, 1:2, 1:3...1:10
. If I click on 1:1
button it show me the content of 1:1
. But when I close the modal the route auto change 1:1
to 1:3...1:10
.Modal
behind main Modal
. I can see only 3-4 lines of back modal.Modal
in same component but in another function.function TafsirModal(props) {
return (
<Modal
{...props}
size="md"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Heading
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>
{props.info}
</div>
</Modal.Body>
<Modal.Footer>
<Button onClick={props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
)
}
const InfoCom = () => {
const { chapterId } = useParams()
let [modalShow, setModalShow] = useState(false);
let [info, setInfo] = useState('')
const { data } = useGetDataQuery(chapterId)
const handleModal = (info_prop) => {
setInfo(info_prop)
setModalShow(true)
}
return (
<>
<div className="container">
<div className="row">
<div className="col-md-12">
{data.map(res => (
<Link to={`/li/${chapterId}/${res.res_key}`} key={res.res_key} >
<div key={res.id} className='card my-2'>
<div className="card-body">
<div className="d-flex flex-row">
<Button onClick={() => handleModal(res.info[0].text)}>
Get Info
</Button>
<TafsirModal
show={modalShow}
onHide={() => setModalShow(false)}
info={info}
/>
</div>
</div>
</div>
</Link>
))}
</div>
</div>
</div>
</>
)
}
export default InfoCom
The issue looks like it's the way you're handling showing your modal with
show={modalShow}
Whenever you click on a button to show your modal all of them are showing because they all have show modal true from modalShow. instead of using showModal state try this:
let [activeModal, setActiveModal] = useState('');
function handleModal(info_prop) {
setInfo(info_prop)
// if you have an id or something use that instead of text in set activeModal
setActiveModal(info_prop)
}
// in map
<Button onClick=(() => handleModal(res.info[0].text)></Button>
<TafsirModal
show={activeModal === res.info[0].text ? true : false}
onHide=(setActiveModal(''))
/>
Another solution that I more commonly use is to render the modal outside of the map towards the top level of the the component and this way you could use the same logic you currently have and this way we are rendering only one modal which would be better in my opinion and easier to read.
We can do this my simply moving <TafsirModal />
up a few levels in the tree
<>
<div className="container">
<div className="row">
<div className="col-md-12">
{data.map(res => (
<Link to={`/li/${chapterId}/${res.res_key}`} key={res.res_key} >
<div key={res.id} className='card my-2'>
<div className="card-body">
<div className="d-flex flex-row">
<Button onClick={() => handleModal(res.info[0].text)}>
Get Info
</Button>
</div>
</div>
</div>
</Link>
))}
</div>
</div>
{activeModal && <TafsirModal
show={modalShow}
onHide={() => setModalShow(false)}
info={info}
/>
}
</div>
</>