Logo

React性能优化useDeferredValue 解决输入卡顿问题

author
YGHub·2024-11-18·4·字数:637 字·阅读时间:3 分钟

在开发 React 应用时,你是否遇到过这样的场景:当用户在搜索框输入时,由于需要实时处理大量数据而导致界面卡顿?今天就来聊聊如何使用 useDeferredValue 优雅地解决这个问题。

一、什么是 useDeferredValue?

useDeferredValue 是 React 18 引入的新 Hook,它可以让我们延迟更新一些不那么重要的内容,优先处理用户交互,从而提升应用的响应性能。

简单来说,它就像是一个"延迟版本"的状态:

jsx
const deferredValue = useDeferredValue(value);
 

二、实际问题场景

假设我们有一个搜索列表,需要根据用户输入实时过滤大量数据:

jsx
function SearchList() {
const [query, setQuery] = useState('');
const [list] = useState(() => generateLargeList(10000)); // 生成大量数据
// 过滤列表
const filteredList = list.filter(item =>
item.text.toLowerCase().includes(query.toLowerCase())
);
return (
<div>
<input
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="搜索..."
/>
<ul>
{filteredList.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
</div>
);
}
 

这段代码的问题在于:每次用户输入都会立即触发过滤操作,当数据量较大时会导致输入卡顿。

三、使用 useDeferredValue 优化

让我们用 useDeferredValue 来改进这个组件:

jsx
import { useState, useDeferredValue, memo } from 'react';
 
// 将列表渲染逻辑抽离为单独的组件
const ListComponent = memo(({ query }: { query: string }) => {
const [list] = useState(() => generateLargeList(10000));
const filteredList = list.filter(item =>
item.text.toLowerCase().includes(query.toLowerCase())
);
return (
<ul>
{filteredList.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
});
 
function SearchList() {
const [query, setQuery] = useState('');
// 创建延迟值
const deferredQuery = useDeferredValue(query);
return (
<div>
<input
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="搜索..."
/>
<ListComponent query={deferredQuery} />
</div>
);
}
 

四、工作原理解析

1.优先级区分

  • 输入框的更新是高优先级的
  • 列表过滤是低优先级的(使用 deferredQuery)

2.更新策略

  • React 会先处理输入框的更新
  • 在空闲时再处理列表过滤
  • 如果有新的输入,会中断当前的过滤操作

3.性能提升

  • 用户输入不会卡顿
  • 列表更新会稍有延迟,但不影响体验

五、进阶使用技巧

1. 配合 Suspense 使用

jsx
function SearchList() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
return (
<div>
<input
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="搜索..."
/>
<Suspense fallback={<Loading />}>
<ListComponent query={deferredQuery} />
</Suspense>
</div>
);
}
 

2. 添加加载状态提示

jsx
function SearchList() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
// 判断是否在加载中
const isStale = query !== deferredQuery;
return (
<div>
<input
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="搜索..."
/>
<div style={{ opacity: isStale ? 0.5 : 1 }}>
<ListComponent query={deferredQuery} />
</div>
{isStale && <Loading />}
</div>
);
}
 

六、最佳实践

1. 何时使用 useDeferredValue

  • 处理大量数据渲染
  • 复杂计算或过滤操作
  • 实时搜索功能
  • 需要保持输入流畅性的场景

2. 性能优化建议

jsx
// 优化前
function SlowComponent({ value }) {
const result = someExpensiveComputation(value);
return <div>{result}</div>;
}
 
// 优化后
const SlowComponent = memo(({ value }) => {
const result = someExpensiveComputation(value);
return <div>{result}</div>;
});
 
function Parent() {
const [value, setValue] = useState('');
const deferredValue = useDeferredValue(value);
return (
<>
<input value={value} onChange={e => setValue(e.target.value)} />
<SlowComponent value={deferredValue} />
</>
);
}
 

3. 注意事项

1.不要过度使用

  • 只在真正需要的地方使用
  • 简单的渲染不需要使用

2.配合 memo 使用

  • 确保延迟的组件被 memo 包裹
  • 避免不必要的重渲染

3.合理的延迟时间

  • 默认情况下 React 会自动选择合适的延迟时间
  • 可以通过 startTransition 自定义优先级

总结

useDeferredValue 是 React 18 中非常实用的性能优化工具,特别适合处理大数据渲染和实时搜索等场景。通过合理使用,可以显著提升应用的响应性能和用户体验。

Preview

4

点个赞 ~

版权申明: © 本文著作权归YGHub所有,未经YGHub网授权许可,禁止第三方以任何形式转载和使用本文内容。