admin管理员组

文章数量:1400116

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 ponent

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 ponent

Share Improve this question edited May 31, 2021 at 20:27 Yoel 7,9956 gold badges31 silver badges63 bronze badges asked May 31, 2021 at 20:17 Gabriel UdoGabriel Udo 2471 gold badge5 silver badges18 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

Two statements will answer virtually every react question:

  1. Don't mutate state (not applicable here)
  2. Lift state up (this is the answer to your question).

Create a context - wrap your application in it, and have any ponent useContext to open a modal with whatever ponents 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 ponent so the context will be available to all your ponents:

const AdminDashboard = () => (
   <ModalProvider>
    <OtherComponents/>
   </ModalProvider>
)

SomeLink, a ponent 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>
   )

}

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 ponent you can use useRef

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.

  1. Create a class with static access.
  2. Place the modal high / outside the dom tree
  3. set the necessary access in the modal ponent

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 ponent

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.)

本文标签: javascriptHow to open modal from anywhere in reactStack Overflow