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.
Information
- Using
react-bootstrapfor modal withhooks - Using
react-router-domfor showroute - Using
useStatehooks to set data from fetched data to modal. - All of code are in one component.
info_prop&infoare different but it works with same data.- I have
importall needed things & don't have anywarning or error - About Data Handling
- First I get data with
useGetDataQuery()usingchapterId. - Map data & destructure
infodata & set to state withsetInfo - Send to Modal props with
info - Handle of sending to
setInfowithhandleModal. I also try without this function. That time I do it ononClick.
- First I get data with
Problem
- Route Problem with map()
- I use a
Buttonto showModal& Wrapped the button withLink. EveryLinkhas a uniqe ID like1:1, 1:2, 1:3...1:10. If I click on1:1button it show me the content of1:1. But when I close the modal the route auto change1:1to1:3...1:10. - I can realize that there it's render a duplicate
Modalbehind mainModal. I can see only 3-4 lines of back modal.
- I use a
- Modal Problem
- When I show 1-5 data with map & click button of popup modal, modal show normally with blur background.
- When I dhow 1-10 data with map & click button of popup modal, background become pure black.(I think it's not normal)
Dependencies
- react-bootstrap v5
- bootstrap v5
- react-router-dom v6
Code
- Code of component.
Modalin 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
CodePudding user response:
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>
</>
