I’ve loosely followed this react modal tutorial.
When I put the Modal inside a loop with multiple links and open the modal, It’s opening all the modals (of course). I’m trying to work out how to open the appropriate modal (for the id)
The Alert component with Modal in loop
export default function Alert({}: Props) {
const { alerts, loading } = useGetAlerts();
const { isShown, toggle } = useModal();
return (
<div className={styles.alertHeader}>
<div className={styles.title}>Alerts</div>
<div className={styles.alertFrame}>
<div className={styles.counter}>{`${alerts?.items.length}`}</div>
<div className={styles.titleFrame}>
<div className={styles.summaryTitle}>
Outstanding <br></br>Alerts
</div>
</div>
</div>
{loading ? (
<SnakeLoader />
) : (
alerts?.items.slice(0, 5).map((a) => (
<div key={`id_${a}`} className={styles.alertFrame}>
<div className={styles.titleFrame} id="titleFrame">
<div className={styles.alertTitle} id="alertTitle">
{' '}
{`${a.message}`}{' '}
</div>
<div className={styles.alertLink} id="alertLink">
<button onClick={toggle}>Click for More</button>
<Modal
isShown={isShown}
hide={toggle}
modalContent={a.message}
headerText={a.id}
/>
</div>
</div>
<div className={styles.alertClose} id="alertClose">
X
</div>
</div>
))
)}
</div>
);
}
The Modal component
import React, { FunctionComponent, useEffect } from 'react';
import ReactDOM from 'react-dom';
import styles from './Modal.module.scss';
//https://nainacodes.com/blog/create-an-accessible-and-reusable-react-modal
export interface ModalProps {
isShown: boolean;
hide: () => void;
modalContent: string;
headerText: string;
}
export const Modal: FunctionComponent<ModalProps> = ({
isShown,
hide,
modalContent,
headerText,
}) => {
const modal = (
<div className={styles.modalContainer}>
<div className={styles.styledModal}>
<div className={styles.header}>
<div className={styles.headerText}>{headerText}</div>
<button className={styles.closeButton} onClick={hide}>
X
</button>
</div>
<div className={styles.content}>{modalContent}</div>
</div>
</div>
);
return isShown ? ReactDOM.createPortal(modal, document.body) : null;
};
The useModal method
export const useModal = () => {
const [isShown, setIsShown] = useState<boolean>(false);
const toggle = () => setIsShown(!isShown);
const id = '';
return {
isShown,
toggle,
id
};
};
Very new to React, any help greatly appreciated
2
Answers
Currently each of your modals use the same piece of state to toggle its visibility,
isShown
. Andtoggle
is the function that changes that state. In order to control the modals individually, we need a separate piece of state and a separate function to toggle that state for each individual modal you have created. One option could be getting rid of theuseModal
hook, and moving bothisShown
andtoggle
into theModal
component itself. This way when eachModal
component is created, it has its own state instead of sharing it from that hook.Basically there is no need to render that much Modal components, render only one of it.
Add 1 extra state variable that will hold the
activeAlertItem
for modal. This variable will be set byClick for More
button click for specifiedalert
.Once set – you are free to use either conditional rendering ie
either whatever else you prefer.
Here is an example (with manual dummy data, sorry):