希望有人可以帮助我朝正确的方向发展,或者指出可能有用的任何文档/学习。
我有两个React组件:
<Widget/>
<Modal/>
在安装<Widget/>
后,<Modal/>
会使用条件渲染进行隐藏(反之亦然),并且在我的ShowModal
状态值中使用相同的布尔值(通过按钮切换此布尔值)。我为此示例here
我遇到麻烦的地方是我有一个异步功能takeScreenShot()
,需要在完全卸载{strong> 和 <Widget/>
安装之前。调用<Modal/>
时,<Widget/>
(刚刚卸载)和<Modal/>
(即将安装)在DOM中都不可见。我需要确保是这种情况,因为我正在截取基础页面的屏幕快照,在该屏幕上我不想在其中包括任何组件。在我的CodeSandbox示例中,屏幕截图功能的输出将呈现灰色背景,而不会显示蓝色或红色框
我尝试过的事情
我试过像这样在takeScreenShot()
组件的useEffect
钩子中运行清理功能。
<Widget/>
但是它不起作用,因为类似于 useEffect(() => {
return () => takeScreenShot();
}, []);
的清理功能可以在组件即将卸载时运行,而不是完全从DOM上完全卸载。这使我的屏幕截图捕获了图像中的卸载组件。有人有想法将我指向正确的方向吗?
答案 0 :(得分:2)
将代码从您的应用程序移动到Modal中,以便在Modal首次加载时被调用。我删除了对useEffect
或useLayoutEffect
的所有引用,尽管模式中仍可能需要useLayoutEffect
。
答案 1 :(得分:1)
您可以尝试在useLayoutEffect
钩中运行它,就像...
useLayoutEffect(() => {
if (!showModal) takeScreenshot();
}, [showModal]);
请参阅... https://reactjs.org/docs/hooks-reference.html#uselayouteffect
根据文档...
签名与useEffect相同,但是它同步触发 在所有DOM突变之后。使用它从DOM中读取布局,并 同步重新渲染。在useLayoutEffect内部安排的更新将 在浏览器有机会绘画之前被同步刷新。
您可能需要保持一个单独的状态,即是否已加载模态,以确保效果挂钩不会在组件的初始加载时执行。
答案 2 :(得分:0)
您可能还有另一个状态布尔值,用于指示是否正在截屏,如果为true则不渲染这两个元素。
是这样的:
() => this.setState({screenshot: true}, () => this.takeScreenshot())
然后在您的takeScreenshot函数中,执行完后将其设置回false
takeScreenshot = () => {
// ...
// ...
this.setState({screenshot: false})
}
现在渲染时
{!screenshot && (showModal ? <Modal /> : <Widget />)}
答案 3 :(得分:0)
这是您可以(并且应该)这样做的方式。
async function takeScreenshot() {
console.log("Taking screenshot...");
return new Promise(resolve => {
window.setTimeout(() => {
resolve();
console.log("Screenshot captured!");
}, 3000);
});
}
function Widget({ onUnmount }) {
React.useEffect(() => {
return () => onUnmount();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <p>Widget</p>;
}
function Modal() {
return <p>Modal</p>;
}
function App() {
const [open, setOpen] = React.useState('widget');
const handleUnmount = async () => {
await takeScreenshot();
setOpen('modal');
}
return (
<React.Fragment>
{open === 'widget' && <Widget onUnmount={handleUnmount} />}
{open === 'modal' && <Modal />}
<button
onClick={() => {
if (open !== "widget") return;
setOpen("");
}}
>
Show modal
</button>
</React.Fragment>
)
}
您可以运行演示here。