React Hooks: Lazy Loading Breaks useLayoutEffect?
Posted
技术标签:
【中文标题】React Hooks: Lazy Loading Breaks useLayoutEffect?【英文标题】: 【发布时间】:2019-07-10 06:29:47 【问题描述】:我的网络应用有一个可以改变高度的顶部导航栏。它固定在屏幕顶部,CSS 位置:固定。要将页面内容移动到其下方,我有一个分隔 div,它会更新其高度以匹配标题的高度,并将其他所有内容向下推。
我正在更新我的应用程序以使用 React 挂钩。我有一个useLayoutEffect
钩子,它检查导航栏的高度并更新垫片的高度以匹配。根据React docs:
与 componentDidMount 或 componentDidUpdate 不同,使用 useEffect 安排的效果不会阻止浏览器更新屏幕。这使您的应用程序感觉更灵敏。大多数效果不需要同步发生。在不常见的情况下(例如测量布局),有一个单独的 useLayoutEffect Hook,其 API 与 useEffect 相同。
我似乎发现,React 延迟加载会中断 useLayoutEffect
。这是一个 CodeSandBox:
https://codesandbox.io/s/5kqxynp564
导航栏隐藏了一个 div,其中包含文本“如果您可以看到此 USELAYOUTEFFECT 正在工作”。使用直接导入时,该文本上方的 div 的大小将与导航栏匹配,将文本向下推到导航栏下方,文本变为可见。使用 React.lazy 时,useLayoutEffect
(在 AppBarHeader.js 中)无法工作。
延迟加载发生在 App.js 中:
//LOADING <COUNTER/> THIS WAY WORKS
// import Counter from "./Counter";
//LAZY LOADING <COUNTER/> THIS WAY BREAKS useLayoutEffect
const CounterPromise = import("./Counter");
const Counter = React.lazy(() => CounterPromise);
我错过了什么?
【问题讨论】:
你能在这里发布一个最小的复制品吗? 当你发现一个错误时,请把它报告给 React repo。 @DanAbramov 我为此创建了一个问题。这个链接在我的回答中。 @DanAbramov 会的。 【参考方案1】:对于Suspense
中的一个组件,这似乎是执行useLayoutEffect
的时间中的一个实际错误,其中一些其他组件是延迟加载的。如果AppBarHeader
被延迟加载而Counter
没有被延迟加载,则它工作正常,但在Counter
延迟加载时,AppBarHeader
的useLayoutEffect
在它完全呈现在 DOM 中之前执行(高度仍然为零)。
This sandbox 以一种非常骇人听闻的方式“修复”它,这有助于进一步证明正在发生的事情。
我将以下内容添加到App.js
:
replaceRefHeader = () =>
this.setState( ref_header: React.createRef() );
;
然后将其传递给Counter
:
<Counter replaceRefHeader=this.replaceRefHeader history=routeProps.history />
然后在Counter
:
const Counter = ( replaceRefHeader ) =>
useLayoutEffect(() =>
replaceRefHeader();
, []);
然后我将[props.ref_header]
放入AppBarHeader
的useLayoutEffect
的依赖数组中。
我并不是建议您应该这样做(尽管这样的事情可以作为临时解决方法)。这只是为了更清楚地展示时间问题。
我在这里记录了一个新问题:https://github.com/facebook/react/issues/14869
【讨论】:
以上是关于React Hooks: Lazy Loading Breaks useLayoutEffect?的主要内容,如果未能解决你的问题,请参考以下文章
React中异步模块api React.lazy和React.Suspense
@apollo/react-hooks 中的 `useSubscription` 方法加载卡住
将参数传递给 react-apollo-hooks useQuery