Skip to main content

19 useTransition基础用法

19 useTransition基础用法

useTransition概念介绍

react提供了useDeferredValue发挥类似防抖节流的作用,而useTransition也是类似的作用,但是该hook是通过降低数据渲染的优先级来达到优先更新其他数据

useTransition用来解决什么问题?

  • 首先给定一个场景,开发时经常会遇到需要联想输入,也就是输入的同时要返回联想搜索结果的列表。
  • 但是这个列表有时返回值非常的长,有时会导致用户输入值的更新缓慢,这里就产生了一个问题,当页面有大量UI更新的时候,怎么处理数据更新不会卡顿。
  • 可以手写防抖节流,防抖有一个弊端,当我们长时间的持续输入(时间间隔小于防抖设置的时间),页面就会长时间都不到响应。而startTransition 可以指定 UI 的渲染优先级,哪些需要实时更新,哪些需要延迟更新。即使用户长时间输入最迟 5s 也会更新一次。
  • 也可以用useDeferredValue,也可以用“可视窗口加载”的方案, 在这里介绍怎么用useTransition解决

useTransition源码

回到useTransition的学习中,首先看一下React源码中的ReactHooks.js

export function useTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
] {
const dispatcher = resolveDispatcher();
return dispatcher.useTransition();
}

再根据引入文件,到react-reconciler/src/ReactInternalTypes.js找到Dispatch里最终调用的useTransition

  useTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
],

上述代码看不懂没关系,本系列教程只是讲述“如何使用Hook”,并不是“Hook源码分析”。^_^

useTransition基本用法

useTransition()函数可以不传参,传参可以传一个毫秒值用来修改最迟更新时间,startTransition回调里的赋值将会被降低优先级。isPending 指示过渡任务何时活跃以显示一个等待状态。

代码形式

const [isPending, startTransition] = useTransition();

startTransition(() => {
setCount(count + 1);
})

传参写法

// 延迟两秒
const [isPending, startTransition] = useTransition(2000);

startTransition(() => {
setCount(count + 1);
})

useTransition使用示例

举例:搜索引擎的关键词联想。一般来说,对于用户在输入框中输入都希望是实时更新的,如果此时联想词比较多同时也要实时更新的话,这就可能会导致用户的输入会卡顿。这样一来用户的体验会变差,这并不是我们想要的结果。

我们将这个场景的状态更新提取出来:一个是用户输入的更新;一个是联想词的更新,这个两个更新紧急程度显然前者大于后者。

这里更新效果可能还不够明显,可以打开浏览器控制台,点击performance insights项,在Measure page load右边有个下拉选项,在cpu那栏的右边下拉选择4x slowdown可以将浏览器运行速度调慢四倍,这样卡顿会明显些。

这里拆分为两个组件,父组件是useTransition的使用,子组件是列表渲染,代码如下:

父组件:

import { useState, useTransition } from 'react'
import ProductList from './components/ProductList'

// 列表数据的生成
export function generateProducts() {
const products: Array<string> = []
for (let i = 0; i < 10000; i++) {
products.push(`Product ${i + 1}`)
}
return products
}

// 列表数据
const dummyProducts = generateProducts()

// 用户输入时过滤搜索,达到一个联想输入的效果
function filterProducts(filterTerm) {
if (!filterTerm) {
return dummyProducts
}
return dummyProducts.filter((product) => product.includes(filterTerm))
}

function App() {
const [isPending, startTransition] = useTransition()
const [filterTerm, setFilterTerm] = useState('')

const filteredProducts = filterProducts(filterTerm)

function updateFilterHandler(event) {
// 列表数据赋值的运行等级
startTransition(() => {
setFilterTerm(event.target.value)
})
}

return (
<div id="app">
<input type="text" onChange={updateFilterHandler} />
{isPending && <p style={{ color: 'white' }}>更新列表。. </p>}
<ProductList products={filteredProducts} />
</div>
)
}

export default App

子组件:

import { useDeferredValue } from "react";

function ProductList({ products }) {
const deferredProducts = useDeferredValue(products);
return (
<ul>
{deferredProducts.map((product, index) => (
<li key={index}>{product}</li>
))}
</ul>
);
}

export default ProductList;

通过这个案例,相信你对useMemo的机制和用法一定有所掌握。


至此,关于useTransition基础用法已经讲完。