我正在学习Relay的教程,这是第3步,就像在https://relay.dev/docs/tutorial/queries-1/上一样。
export default function Newsfeed() {
console.log("HERE 0")
const data = useLazyLoadQuery(
NewsfeedQuery,
{}
)
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应用程序是这样的,
const [data, setData] = useState(null);
useEffect(() => {
// fetching data here
}, []);
return (
<div>{
data && ... // display the data
}</div>
);
型
也就是说,它会一直运行到函数的末尾,不显示任何内容,因为data
为空。一旦data
是由setData
引起的,这会导致重新渲染,那么组件就会显示一些内容。所以它是一个运行两次直到函数完成的过程。
上面的useLazyLoadQuery()
代码看起来不像是“运行两次完成”。它看起来像是神奇地可以在中间导致重新渲染。
事实上,它看起来并不像是“懒惰”的,它看起来像是在勤奋地工作(以前阻塞I/O是这样的)。
它是如何产生作用的?
2条答案
按热度按时间cnh2zyt31#
这是因为Relay使用了Suspense。从您链接的教程:
Relay使用Suspense显示加载指示器,直到数据可用。
当使用Suspense获取数据时(抛出promise或使用新的
use
钩子),如果React需要一些还没有的数据,它将停止渲染('suspend')组件。React将显示最近Suspense边界的fallback
,并在加载数据时重新渲染子树。在你的例子中,
useLazyLoadQuery
在后台请求一些数据,Next.js处理所有与Suspense相关的东西,所以这可能不太明显。但是如果你试图在普通的React项目中使用useLazyLoadQuery
(即没有框架),你可能会从React中得到错误,因为它无法找到Suspense边界,除非你显式定义一个。我做了一些关于Suspense的研究,前一段时间写了一个article,如果你对Suspense的工作原理感兴趣,这可能是一个很好的起点。
qybjjes12#
深入了解relay documentation,其中指出:
查看教程中的存储库,我可以看到该应用程序被 Package 在
<React.Suspense fallback={<LoadingSpinner />}>
中这意味着在
useLazyLoadQuery
下的所有代码都不会被执行,直到它发出组件 * 就绪 * 的信号。上面的所有代码都将被执行,这就是为什么您会看到
"HERE 0"
两次。渲染过程如下所示
1.渲染
Newsfeed
组件(从App.tsx
)console.log("HERE 0");
个React.Suspense
,直到useLazyLoadQuery
准备就绪,并 * 暂停 *Newsfeed
组件中的所有其他代码1.当
useLazyLoadQuery
有数据时,它将触发重新呈现Newsfeed
组件1.重新渲染
Newsfeed
组件console.log("HERE 0");
个React.Suspense
没有启动,因为useLazyLoadQuery
有数据console.log("HERE 1", JSON.stringify(data));
个1.......
Newsfeed
组件的其余部分