I want to fetch and suspense use by use
of react 18.3.0, but occurred multi re-rendering.
我想通过使用react 18.3.0来获取和暂停使用,但发生了多次重新渲染。
- react: 18.3.0-canary-3ff846d10-20230724
- next: 13.4.12
This code is render SuspenseTest
output to the console multiple times (about 5 to 8 times) until render Done
.
此代码将多次(大约5到8次)呈现挂起测试输出到控制台,直到呈现完成。
// src/pages/index.tsx
import { Suspense } from "react"
import Head from "next/head"
import SuspenseTest from "@/components/modules/SuspenseTest"
const Top = (): JSX.Element => {
return (
<>
<Head>
<title>Suspense Test</title>
</Head>
<main>
<Suspense fallback={<div>Now Loading...</div>}>
<SuspenseTest />
</Suspense>
</main>
</>
)
}
export default Top
// src/components/modules/SuspenseTest/index.tsx
import { use } from "react"
const fetcher = (): Promise<string> => {
return new Promise((resolve) =>
setTimeout(() => {
resolve("Done")
}, 5000),
)
// What I actually want to do is the following process
// return axiosClient
// .get("/articles")
// .then((response) => {
// return response.data as Promise<Article[]>
// })
// .catch((error) => console.error(error))
}
const SuspenseTest = (): JSX.Element => {
console.log("render SuspenseTest")
const message = use<string>(fetcher())
return <div>{message}</div>
}
export default SuspenseTest
I expected only once rendering.
我以为只会渲染一次。
I tried use React.memo
, useMemo
, useCallback
, but that doesn't seem to be the point (maybe).
我试过使用React.Memo、useMemo、useCallback,但这似乎不是重点(可能)。
I would like to avoid using external libraries as much as possible.
我想尽量避免使用外部库。
Thank you.
谢谢。
更多回答
优秀答案推荐
If your Layout
component re-renders, then SuspenseTest
will also re-render, which means multiple console.log
output.
如果您的布局组件重新呈现,那么SuspenseTest也将重新呈现,这意味着多个console.log输出。
If you need to prevent that, use useEffect
hook, like:
如果需要防止这种情况,请使用Use Effect挂钩,如下所示:
import { useEffect } from 'react'
const SuspenseTest = (): JSX.Element => {
const [result, setResult] = useState('Now Loading...')
useEffect(() => {
setTimeout(() => setResult('Done'), 5000)
}, [])
return <div>{result}</div>
}
The second argument for useEffect
is an array of dependencies (in this case []
), and the component shall re-render only after the values in this array changes.
UseEffect的第二个参数是一个依赖项数组(在本例中为[]),只有在该数组中的值更改后,组件才会重新呈现。
Also, since your intention is to show Now Loading...
for 5 seconds, better to use a setTimeout
for this.
另外,既然你的意图是展示现在正在装货...在5秒内,最好使用setTimeout。
更多回答
Maybe this code doesn't display Now Loading...
?
可能现在加载时此代码不显示...?
Because thats a fallback and will be rendered only until SuspenseTest
hasn't finished loading. But now since no error, it's rendered immediately, and as such, fallback doesn't have time to be rendered. Hope that clarifies!
因为这是一种后备方案,只有在SuspenseTest尚未完成加载时才会呈现。但现在由于没有错误,它会立即呈现,因此,回退没有时间呈现。希望这能澄清!
Sorry. I couldn't understand what you said. I want to display Now Loading...
for 5000ms, and then display Done
. Doesn't Suspense
render the fallback instead of SuspenseTest
when it receives a pending Promise?
抱歉的。我听不懂你说的话。我想要显示现在正在加载...5000毫秒,然后显示完成。悬念不会在收到悬而未决的承诺时呈现后备状态而不是SuspenseTest吗?
Yes, Suspense
will try to render the fallback until SuspenseTest
finish rendering. But the issue here is that SuspenseTest
is such a simple element that, it wont take any time to render. Meaning, you won't see that fallback.
可以,在SuspenseTest完成渲染之前,Suspense将尝试渲染回退。但这里的问题是,SuspenseTest是一个如此简单的元素,不需要任何时间来呈现。这意味着,你不会看到这种后退。
I'm Sorry, I still don't understand. Ok, I edited my sample code. I think SuspenseTest
is not simple element anymore. My Sample Code work "display Now Loading...
for 5000ms, and then display Done
", but this code problem is multi re-rendering. The code you provided does not meet my expectations of rendering fallback instead of SuspenseTest
while fetching.
对不起,我还是不明白。好的,我编辑了我的示例代码。我认为悬浮测试已经不再是简单的元素了。我的示例代码工作“Display Now Loading...for 5000ms,然后显示Done”,但这个代码问题是多重渲染。您提供的代码不符合我在提取时呈现回退而不是SuspenseTest的预期。
我是一名优秀的程序员,十分优秀!