reactjs 为什么useLazyLoadQuery()看起来像阻塞,并且会导致重新呈现?

lp0sw83n  于 2023-11-18  发布在  React
关注(0)|答案(2)|浏览(109)

我正在学习Relay的教程,这是第3步,就像在https://relay.dev/docs/tutorial/queries-1/上一样。

  1. export default function Newsfeed() {
  2. console.log("HERE 0")
  3. const data = useLazyLoadQuery(
  4. NewsfeedQuery,
  5. {}
  6. )
  7. console.log("HERE 1", JSON.stringify(data));

字符串
在Google Chrome的开发控制台中,我可以看到以下内容:
x1c 0d1x的数据
所以事情很奇怪:它看起来像是能够到达“HERE 0”,然后获取数据,就像它正在阻塞I/O一样(网络提取)(术语阻塞I/O的意思是,就像在过去,当我们做一个Unix系统调用read()时,这个函数在它完成阅读任务之前永远不会返回,不像现在,我们执行JavaScript fetch()并设置then处理程序,fetch()立即返回,而不从网络中阅读一个字节),然后再次重新呈现组件:请注意,它没有转到“HERE 1”,而是再次执行了“HERE 0”,然后是“HERE 1”。
这和React的工作原理大不相同。传统的React应用程序是这样的,

  1. const [data, setData] = useState(null);
  2. useEffect(() => {
  3. // fetching data here
  4. }, []);
  5. return (
  6. <div>{
  7. data && ... // display the data
  8. }</div>
  9. );


也就是说,它会一直运行到函数的末尾,不显示任何内容,因为data为空。一旦data是由setData引起的,这会导致重新渲染,那么组件就会显示一些内容。所以它是一个运行两次直到函数完成的过程。
上面的useLazyLoadQuery()代码看起来不像是“运行两次完成”。它看起来像是神奇地可以在中间导致重新渲染。
事实上,它看起来并不像是“懒惰”的,它看起来像是在勤奋地工作(以前阻塞I/O是这样的)。
它是如何产生作用的?

cnh2zyt3

cnh2zyt31#

这是因为Relay使用了Suspense。从您链接的教程:
Relay使用Suspense显示加载指示器,直到数据可用。
当使用Suspense获取数据时(抛出promise或使用新的use钩子),如果React需要一些还没有的数据,它将停止渲染('suspend')组件。React将显示最近Suspense边界的fallback,并在加载数据时重新渲染子树。
在你的例子中,useLazyLoadQuery在后台请求一些数据,Next.js处理所有与Suspense相关的东西,所以这可能不太明显。但是如果你试图在普通的React项目中使用useLazyLoadQuery(即没有框架),你可能会从React中得到错误,因为它无法找到Suspense边界,除非你显式定义一个。
我做了一些关于Suspense的研究,前一段时间写了一个article,如果你对Suspense的工作原理感兴趣,这可能是一个很好的起点。

qybjjes1

qybjjes12#

深入了解relay documentation,其中指出:

  • 为了在获取查询时呈现加载状态,我们依赖于React Suspense。Suspense是React中的一个新特性,它允许组件中断或“挂起”呈现,以便等待某些异步资源。(例如代码、图像或数据);当组件“挂起”时,它向React指示该组件还没有“准备好”呈现,直到它等待的异步资源被加载后,React才会重新呈现组件。*

查看教程中的存储库,我可以看到该应用程序被 Package 在<React.Suspense fallback={<LoadingSpinner />}>
这意味着在useLazyLoadQuery下的所有代码都不会被执行,直到它发出组件 * 就绪 * 的信号。
上面的所有代码都将被执行,这就是为什么您会看到"HERE 0"两次。
渲染过程如下所示
1.渲染Newsfeed组件(从App.tsx

  1. console.log("HERE 0");
  2. React.Suspense,直到useLazyLoadQuery准备就绪,并 * 暂停 * Newsfeed组件中的所有其他代码
    1.当useLazyLoadQuery有数据时,它将触发重新呈现Newsfeed组件
    1.重新渲染Newsfeed组件
  3. console.log("HERE 0");
  4. React.Suspense没有启动,因为useLazyLoadQuery有数据
  5. console.log("HERE 1", JSON.stringify(data));
    1....... Newsfeed组件的其余部分
展开查看全部

相关问题