自学内容网 自学内容网

React 中hooks之useTransition使用总结

目录

  1. 概述
  2. 基本用法
  3. 使用场景
  4. 最佳实践
  5. 注意事项

概述

什么是 useTransition?

useTransition 是 React 18 引入的新 Hook,用于标记非紧急的状态更新。它允许组件在状态转换期间保持响应,通过将某些更新标记为"过渡"来推迟它们的渲染。

主要特点

  • 保持 UI 响应性
  • 区分紧急和非紧急更新
  • 提供加载状态指示器
  • 不会阻塞用户交互

基本用法

1. 基本语法

import { useTransition } from 'react';

function MyComponent() {
  const [isPending, startTransition] = useTransition();
  const [count, setCount] = useState(0);

  const handleClick = () => {
    startTransition(() => {
      setCount(c => c + 1);  // 这个更新被标记为过渡,当某次更新造成页面阻塞时,用户点击其他组件操作,此时会降低此次更新的优先级,不阻塞页面渲染先更新优先级高的操作,startTransition中只能写同步的代码,异步代码会打断低优先级,比如不能使用setTimeout
    });
  };

  return (
    <div>
      {isPending && <Spinner />}
      <button onClick={handleClick}>Increment</button>
      <p>Count: {count}</p>
    </div>
  );
}//isPending为true是表示当前渲染阻塞避免页面出现卡顿现象先显示loading状态组件,直到isPending为false时将展示渲染好的组件

2. 带加载状态的示例

function SearchResults() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
    // 立即更新输入值(紧急更新)
    setQuery(e.target.value);

    // 将搜索结果更新标记为过渡(非紧急更新)
    startTransition(() => {
      // 模拟搜索操作
      const searchResults = performSearch(e.target.value);
      setResults(searchResults);
    });
  };

  return (
    <div>
      <input value={query} onChange={handleSearch} />
      {isPending ? (
        <div>Loading...</div>
      ) : (
        <ul>
          {results.map(result => (
            <li key={result.id}>{result.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

使用场景

1. 大量数据渲染

function DataGrid() {
  const [data, setData] = useState([]);
  const [isPending, startTransition] = useTransition();
  const [filter, setFilter] = useState('');

  const handleFilterChange = (newFilter: string) => {
    setFilter(newFilter);  // 立即更新过滤条件

    startTransition(() => {
      // 延迟大量数据的过滤和渲染
      const filteredData = processLargeDataSet(newFilter);
      setData(filteredData);
    });
  };

  return (
    <div>
      <input 
        value={filter} 
        onChange={e => handleFilterChange(e.target.value)} 
      />
      {isPending ? (
        <LoadingGrid />
      ) : (
        <VirtualizedGrid data={data} />
      )}
    </div>
  );
}

2. 路由切换

function App() {
  const [isPending, startTransition] = useTransition();
  const [currentPage, setCurrentPage] = useState('home');

  const navigate = (page: string) => {
    // 立即更新导航状态
    startTransition(() => {
      setCurrentPage(page);
    });
  };

  return (
    <div>
      <Navigation onNavigate={navigate} />
      {isPending ? (
        <PageTransitionSpinner />
      ) : (
        <Page name={currentPage} />
      )}
    </div>
  );
}

3. 表单验证

function ComplexForm() {
  const [formData, setFormData] = useState({});
  const [errors, setErrors] = useState({});
  const [isPending, startTransition] = useTransition();

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    
    // 立即更新表单值
    setFormData(prev => ({
      ...prev,
      [name]: value
    }));

    // 将复杂的验证逻辑标记为过渡
    startTransition(() => {
      const validationErrors = validateFormField(name, value);
      setErrors(prev => ({
        ...prev,
        [name]: validationErrors
      }));
    });
  };

  return (
    <form>
      <input 
        name="email" 
        onChange={handleChange} 
        value={formData.email || ''} 
      />
      {isPending ? (
        <ValidatingIndicator />
      ) : (
        errors.email && <ErrorMessage error={errors.email} />
      )}
    </form>
  );
}

最佳实践

  1. 区分更新优先级
function UserProfile() {
  const [isPending, startTransition] = useTransition();
  
  const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    // 高优先级:直接更新输入值
    setInputValue(e.target.value);
    
    // 低优先级:更新预览
    startTransition(() => {
      setPreviewData(generatePreview(e.target.value));
    });
  };
}
  1. 合理使用 isPending
function LoadingStates() {
  const [isPending, startTransition] = useTransition();
  
  return (
    <div>
      {/* 使用骨架屏而不是简单的加载指示器 */}
      {isPending ? (
        <Skeleton />
      ) : (
        <Content />
      )}
    </div>
  );
}

注意事项

  1. 不要在 transition 中包含紧急更新
// ❌ 错误示例
startTransition(() => {
  setInputValue(e.target.value);  // 这应该是紧急更新
});

// ✅ 正确示例
setInputValue(e.target.value);    // 紧急更新
startTransition(() => {
  setSearchResults(search(e.target.value));  // 非紧急更新
});
  1. 避免不必要的 transition
// ❌ 不需要 transition
startTransition(() => {
  setCount(count + 1);  // 简单的状态更新不需要 transition
});

// ✅ 适合使用 transition
startTransition(() => {
  setFilteredItems(items.filter(complexFilter));  // 复杂计算
});

总结

  1. useTransition 适用场景:

    • 大量数据处理
    • 复杂 UI 更新
    • 后台计算
    • 非阻塞渲染
  2. 主要优势:

    • 提升用户体验
    • 保持 UI 响应性
    • 优化渲染性能
    • 提供加载状态
  3. 使用建议:

    • 合理区分更新优先级
    • 适当处理加载状态
    • 避免过度使用
    • 配合其他性能优化手段

原文地址:https://blog.csdn.net/qq_34645412/article/details/145269727

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!