Reputation: 237
I have a modal when opened, display auth user data, currently, I can only open the modal on the dashboard, but I want to be able to render it from anywhere in my application. How do I achieve this?
Dashboard
const [visible, setVisible] = useState(false)
const trigerModal = ()=>(
<ModalCustom visible={visible} setVisible={setVisible}>
<form>
<>
<h3>Select an Account</h3>
<ul className="account">
{accounts && accounts.map((item, i) => (
<li key={item.id}>
<h3>{item.name}</h3>
<h3>{item.email}</h3>
<h3> {item.phone}</h3>
</li>
))}
</ul>
<br />
</>
</form>
</ModalCustom>
)
return(
<div>
{trigerModal()}
<button onClick={()=> setVisible(true)}>Open modal</button
</div>
)
Profile
how do trigger the modal from this component
Upvotes: 5
Views: 3972
Reputation: 55643
Two statements will answer virtually every react question:
Create a context - wrap your application in it, and have any component useContext
to open a modal with whatever components you want it in:
export const ModalContext = React.createContext();
const ModalProvider = ({children}) => {
const [modalContent,setModalContent] = useState();
return (
<ModalContext.Provider value={
useMemo(() => ({
hide:() => setModalContent(),
open:setModalContent
}),[]
}>
{modalContent ? <Modal>{modalContent}</Modal> : null}
{children}
</ModalContext.Provider>
)
}
Wrap you application in the ModalProvider
component so the context will be available to all your components:
const AdminDashboard = () => (
<ModalProvider>
<OtherComponents/>
</ModalProvider>
)
SomeLink
, a component that is anywhere inside AdminDashboard
can use React.useContext
to access the state in ModalProvider
const SomeLink = () => {
const { open } = React.useContext(ModalContext);
return (
<button onClick={() => open(<SomeModalContent/>)}>Click to Open!</button>
)
}
Upvotes: 5
Reputation: 165
Not the most "react"-like solution but I don't like to solve everything "react"-like so here is how I solved it for my specific usecase.
HelperClass
export class ModalHelper {
private static openFunction: (state: boolean) => void;
public static setOpenFunction(f: (state: boolean) => void) {
ModalHelper.openFunction = f;
}
public static setOpen(state: boolean) {
if (ModalHelper.openFunction) {
ModalHelper.openFunction(state);
} else {
console.error("ModalHelper called before setOpenFunction")
}
}
}
Sample Modal component
export function ExplainerModal() {
const [open, setOpen] = useState(false);
useEffect(() => {
ModalHelper.setOpenFunction(setOpen);
return () => {
ModalHelper.setOpenFunction(undefined);
};
}, []);
return <>I'm a modal</>
}
Call from anywhere
ModalHelper.setOpen(true);
Now keep in mind this only works for one modal, but can of course be further adapted to handle multiple modals (e.g. by adding a dict for the functions etc.)
Upvotes: 0
Reputation: 7985
If you want to access it from anywhere You need to use Global State (like Redux or Mobx)
If you want to control this from parent component you can use useRef
Upvotes: 0