如何通过调用函数呈现弹出窗口?
How to render a popup by calling a function?
我想在 React 中渲染一个元素 通过调用一个函数。
通常您会使用一个组件(假设是 Popup
),该组件从状态中获取一个布尔值以使其显示或不显示,并使用一些回调处理程序更改它。像这样:
import React, { useState } from "react";
import Popup from "somecomponentlibrary";
import { Button } from "pathtoyourcomponents";
export const SomeComponent = () => {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => { setOpen(true); }}>
this opens a modal
</Button>
<Popup type={"info"} open={open} timeout={1000}>
text within modal
<Button onClick={() => { setOpen(false); }}></Button>
</Popup>
</>
);
};
我想知道是否可以像上面那样调用一些方法在屏幕上显示它,而不是像上面那样在组件中返回它:
import React from "react";
import { Button, popup } from "pathtoyourcomponents";
export const SomeComponent = () => {
return (
<>
<Button onClick={() => { popup.info("text within modal", 1000); }}>
this opens a modal
</Button>
</>
);
};
如何编写 popup
函数以便以这种方式在 DOM 中呈现 Popup
组件?
弹出窗口可以呈现为一个新的单独的 React 应用程序,但仍然可以与主应用程序共享状态,如下所示。
import React, { useEffect } from "react";
import { render, unmountComponentAtNode } from "react-dom";
const overlay = {
top: "0",
height: "100%",
width: "100%",
position: "fixed",
backgroundColor: "rgb(0,0,0)"
};
const overlayContent = {
position: "relative",
top: "25%",
textAlign: "center",
margin: "30px",
padding: "20px",
backgroundColor: "white"
};
let rootNode;
let containerNode;
function Modal({ children }) {
useEffect(() => {
return () => {
if (rootNode) {
rootNode.removeChild(containerNode);
}
containerNode = null;
};
}, []);
function unmountModal() {
if (containerNode) {
unmountComponentAtNode(containerNode);
}
}
return (
<div style={overlay}>
<div style={overlayContent}>
{children}
<button onClick={unmountModal}>Close Modal</button>
</div>
</div>
);
}
/* additional params like props/context can be passed */
function renderModal(Component) {
if (containerNode) {
return;
}
containerNode = document.createElement("div");
rootNode = document.getElementById("root");
containerNode.setAttribute("id", "modal");
rootNode.appendChild(containerNode);
render(<Modal>{Component}</Modal>, containerNode);
}
const App = () => {
const ModalBody = <p>This is a modal</p>;
return (
<div>
<button onClick={() => renderModal(ModalBody)}>Open Modal</button>
</div>
);
};
render(<App />, document.getElementById("root"));
不久前我为一个弹出窗口做了命令式API,它允许你等待它直到它关闭,甚至接收调用者的输入(你也可以发回用户按下的按钮):
const PopupContext = createContext()
export const PopupProvider = ({children}) => {
const [open, setOpen] = useState(false)
const [input, setInput] = useState('')
const resolver = useRef()
const handleOpen = useCallback(() => {
const { promise, resolve } = createDeferredPromise()
resolver.current = resolve
setInput('')
setOpen(true)
return promise
}, [])
const handleClose = useCallback(() => {
resolver.current?.(input)
setOpen(false)
}, [])
return <PopupContext.Provider value={handleOpen}>
{children}
<Popup type={"info"} open={open} timeout={1000} onClose={handleClose}>
<input value={input} onChange={e => setValue(e.target.value)}/>
<Button onClick={handleClose}/>
</Popup>
</PopupContext.Provider>
}
export const usePopup = () => {
const context = useContext(PopupContext);
if (!context)
throw new Error('`usePopup()` must be called inside a `PopupProvider` child.')
return context
}
// used to let await until the popup is closed
const createDeferredPromise = func => {
let resolve, reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
func?.(resolve, reject)
})
return { promise, resolve, reject }
}
您可以使用提供商包装您的应用:
return <PopupProvider>
<App/>
</PopupProvider>
并在您的功能组件中使用它:
const MyComponent = props => {
const popup = usePopup()
return <Button onClick={e => {
const input = await popup()
console.log('popup closed with input: ' + input)
}/>
}
你可以做更多有趣的事情,比如将提示文本传递给弹出函数以在弹出窗口中显示等。我会把它留给你。
您可能还想记住被包装的顶级组件,以避免在弹出窗口中重新呈现整个应用程序 open/close。
调用函数时可以使用ReactDOM.render渲染弹窗:
const node = document.createElement("div");
const popup = (message, {type, timeout}) => {
document.body.appendChild(node);
const PopupContent = () => {
return (
<Popup type={type} open={true} timeout={timeout}>
{message}
<button
onClick={clear}
>Close</button>
</Popup >
);
};
const clear = () => {
ReactDOM.unmountComponentAtNode(node);
node.remove();
}
ReactDOM.render(<PopupContent/>, node);
};
然后调用弹窗函数:
<Button onClick={() => { popup("text within modal", {type: "info", timeout: 1000}); }}>
this opens a modal
</Button>
是的,我想你可以做到。
例如:
使用弹窗组件
import React, { useState } from "react";
import Popup from "somecomponentlibrary";
import { Button } from "pathtoyourcomponents";
export const SomeComponent = () => {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => { setOpen(true); }}>
this opens a modal
</Button>
<Popup type={"info"} open={open} timeout={1000}>
text within modal
<Button onClick={() => { setOpen(false); }}></Button>
</Popup>
</>
);
};
定义弹窗组件
const Popup = (props) => {
return(
<div style={{zIndex:props.open?"-100":"100", transition: `all ${props.timeout /
1000}s`, opacity: props.open?1:0}}>
{props.children}
</div>
)
}
我觉得你可以自定义你喜欢的动画效果。
我想在 React 中渲染一个元素 通过调用一个函数。
通常您会使用一个组件(假设是 Popup
),该组件从状态中获取一个布尔值以使其显示或不显示,并使用一些回调处理程序更改它。像这样:
import React, { useState } from "react";
import Popup from "somecomponentlibrary";
import { Button } from "pathtoyourcomponents";
export const SomeComponent = () => {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => { setOpen(true); }}>
this opens a modal
</Button>
<Popup type={"info"} open={open} timeout={1000}>
text within modal
<Button onClick={() => { setOpen(false); }}></Button>
</Popup>
</>
);
};
我想知道是否可以像上面那样调用一些方法在屏幕上显示它,而不是像上面那样在组件中返回它:
import React from "react";
import { Button, popup } from "pathtoyourcomponents";
export const SomeComponent = () => {
return (
<>
<Button onClick={() => { popup.info("text within modal", 1000); }}>
this opens a modal
</Button>
</>
);
};
如何编写 popup
函数以便以这种方式在 DOM 中呈现 Popup
组件?
弹出窗口可以呈现为一个新的单独的 React 应用程序,但仍然可以与主应用程序共享状态,如下所示。
import React, { useEffect } from "react";
import { render, unmountComponentAtNode } from "react-dom";
const overlay = {
top: "0",
height: "100%",
width: "100%",
position: "fixed",
backgroundColor: "rgb(0,0,0)"
};
const overlayContent = {
position: "relative",
top: "25%",
textAlign: "center",
margin: "30px",
padding: "20px",
backgroundColor: "white"
};
let rootNode;
let containerNode;
function Modal({ children }) {
useEffect(() => {
return () => {
if (rootNode) {
rootNode.removeChild(containerNode);
}
containerNode = null;
};
}, []);
function unmountModal() {
if (containerNode) {
unmountComponentAtNode(containerNode);
}
}
return (
<div style={overlay}>
<div style={overlayContent}>
{children}
<button onClick={unmountModal}>Close Modal</button>
</div>
</div>
);
}
/* additional params like props/context can be passed */
function renderModal(Component) {
if (containerNode) {
return;
}
containerNode = document.createElement("div");
rootNode = document.getElementById("root");
containerNode.setAttribute("id", "modal");
rootNode.appendChild(containerNode);
render(<Modal>{Component}</Modal>, containerNode);
}
const App = () => {
const ModalBody = <p>This is a modal</p>;
return (
<div>
<button onClick={() => renderModal(ModalBody)}>Open Modal</button>
</div>
);
};
render(<App />, document.getElementById("root"));
不久前我为一个弹出窗口做了命令式API,它允许你等待它直到它关闭,甚至接收调用者的输入(你也可以发回用户按下的按钮):
const PopupContext = createContext()
export const PopupProvider = ({children}) => {
const [open, setOpen] = useState(false)
const [input, setInput] = useState('')
const resolver = useRef()
const handleOpen = useCallback(() => {
const { promise, resolve } = createDeferredPromise()
resolver.current = resolve
setInput('')
setOpen(true)
return promise
}, [])
const handleClose = useCallback(() => {
resolver.current?.(input)
setOpen(false)
}, [])
return <PopupContext.Provider value={handleOpen}>
{children}
<Popup type={"info"} open={open} timeout={1000} onClose={handleClose}>
<input value={input} onChange={e => setValue(e.target.value)}/>
<Button onClick={handleClose}/>
</Popup>
</PopupContext.Provider>
}
export const usePopup = () => {
const context = useContext(PopupContext);
if (!context)
throw new Error('`usePopup()` must be called inside a `PopupProvider` child.')
return context
}
// used to let await until the popup is closed
const createDeferredPromise = func => {
let resolve, reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
func?.(resolve, reject)
})
return { promise, resolve, reject }
}
您可以使用提供商包装您的应用:
return <PopupProvider>
<App/>
</PopupProvider>
并在您的功能组件中使用它:
const MyComponent = props => {
const popup = usePopup()
return <Button onClick={e => {
const input = await popup()
console.log('popup closed with input: ' + input)
}/>
}
你可以做更多有趣的事情,比如将提示文本传递给弹出函数以在弹出窗口中显示等。我会把它留给你。
您可能还想记住被包装的顶级组件,以避免在弹出窗口中重新呈现整个应用程序 open/close。
调用函数时可以使用ReactDOM.render渲染弹窗:
const node = document.createElement("div");
const popup = (message, {type, timeout}) => {
document.body.appendChild(node);
const PopupContent = () => {
return (
<Popup type={type} open={true} timeout={timeout}>
{message}
<button
onClick={clear}
>Close</button>
</Popup >
);
};
const clear = () => {
ReactDOM.unmountComponentAtNode(node);
node.remove();
}
ReactDOM.render(<PopupContent/>, node);
};
然后调用弹窗函数:
<Button onClick={() => { popup("text within modal", {type: "info", timeout: 1000}); }}>
this opens a modal
</Button>
是的,我想你可以做到。
例如:
使用弹窗组件
import React, { useState } from "react";
import Popup from "somecomponentlibrary";
import { Button } from "pathtoyourcomponents";
export const SomeComponent = () => {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => { setOpen(true); }}>
this opens a modal
</Button>
<Popup type={"info"} open={open} timeout={1000}>
text within modal
<Button onClick={() => { setOpen(false); }}></Button>
</Popup>
</>
);
};
定义弹窗组件
const Popup = (props) => {
return(
<div style={{zIndex:props.open?"-100":"100", transition: `all ${props.timeout /
1000}s`, opacity: props.open?1:0}}>
{props.children}
</div>
)
}
我觉得你可以自定义你喜欢的动画效果。