在开发页面中,我们很常用的一种加载方式是使用 Suspense,在 fallback 属性设置一个加载标签,这样当我们需要远程加载数据时,可以显示 fallback 内容,当数据请求完成时,加载完整页面。但这种加载方式的一个缺点是在加载过程中阻碍了交互性,比如当用户在加载数据过程中,因等待时间较长,想要选择其他页面或者进行其他操作,就无法操作。这时候,我们可以使用 React 中的 useTransition。下面我们来介绍一下如何使用 useTransition。
useTransition
useTransition 是一个 Hooks, 且不接受任何参数。
const [isPending, startTransition] = useTransition();
比如,在我们进行 Tab 内容切换时,我们可以对 Tab 组件的 onClick 事件进行 startTransition()。
首先我们定一个页面,该页面右 Home,Contact,和 About 三个内容。当我们点击 Tab 的时候,自动对内容进行切换。该例子的灵感来源于 React 官网。
Page 页面内容:
import { useState, useTransition } from 'react';
import TabButton from './TabButton'
import AboutTab from './AboutTab';
import HomeTab from './HomeTab';
import ContactTab from './ContactTab';
export default function Page() {
const [tab, setTab] = useState('about');
const [isPending, startTransition] = useTransition();
function setTabContent(content) {
startTransition(() => { // 使用 startTransition 使点击交互不阻塞
setTab(content)
})
}
return (
<>
<TabButton onClick={() => {
setTabContent('about')
}}
>about</TabButton>
<TabButton onClick={() => {
setTabContent('contact')
}}
>contact</TabButton>
<TabButton onClick={() => {
setTabContent('home')
}}
>home</TabButton>
{tab == 'about' && <AboutTab />}
{tab == 'contact' && <ContactTab />}
{tab == 'home' && <HomeTab />}
</>
)
}
TabButton 组件:
export default function TabButton({isActive, onClick, children}) {
if(isActive) { // 区分是否 Active,如果 Active,则不需要为该 Tab 添加点击事件
return(
<b>{children</b>
)
}
return(
<button onClick={() => onClick()}>{children}</button>
)
}
ContactTab 页面内容:
import { memo } from 'react'
const ContactTab = memo(function() { // 使用 memo 从而 props 不变化时,组件不变
let contacts = []
for (let i = 0; i < 500; i++) {
contacts.push(<SlowPost key={i} index={i} />);
}
return (
<ul className="contacts">
{contacts}
</ul>
)
})
function SlowPost({index}) {
let startTime = performance.now()
while(performance.now() - startTime < 1) { // 延迟模仿加载缓慢情况
}
return(
<li className="item">
Post {index + 1}
</li>
)
}
export default ContactTab;
About 和 Home 设置为静态页面,内容如下:
export default function HomeTab() {
return (
<p>home</p>
)
}
这时候我们点击 TabButton,即使 Contact 页面内容加载延迟,但是点击 Tab 的事件依然可以响应,这是因为我们为点击事件包裹在 startTransiton() 方法里,该方法不返回任何值。