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-bootstrap
for modal withhooks
- Using
react-router-dom
for showroute
- Using
useState
hooks to set data from fetched data to modal. - All of code are in one component.
info_prop
&info
are different but it works with same data.- I have
import
all needed things & don't have anywarning or error
- About Data Handling
- First I get data with
useGetDataQuery()
usingchapterId
. - Map data & destructure
info
data & set to state withsetInfo
- Send to Modal props with
info
- Handle of sending to
setInfo
withhandleModal
. 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
Button
to showModal
& Wrapped the button withLink
. EveryLink
has a uniqe ID like1:1, 1:2, 1:3...1:10
. If I click on1:1
button it show me the content of1:1
. But when I close the modal the route auto change1:1
to1:3...1:10
. - I can realize that there it's render a duplicate
Modal
behind 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.
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
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>
</>