ReactuseTransition Hooks 使用来处理 “过渡状态”的,它允许将某些更新标记为 “非紧急“, 从而使用户界面在执行某些耗时任务时依旧保持流畅。它可以帮助我们区分 ”高优先级“和 ”低优先级“ 的更新,避免因为某个任务耗时过长导致整个界面卡顿。

  • 高优先级更新:立刻影响用户体验的更新,例如点击按钮后按钮的视觉反馈
  • 低优先级更新: 可以稍后完成的更新,例如渲染大量数据或繁重的组件重绘

useTransition 通过提供 startTransition 方法,可以将一些非紧急的任务标记为 ”低优先级“,React 会在完成高优先级任务后再去执行低优先级的任务

使用方式

const [isPending, startTransition] = useTransition();
startTransition(() => {
 setCount(count + 1);
});

应用场景

加入有一个 搜索框,当用户输入内容时,需要根据输入筛选显示一些数据,如果筛选很复杂,就会导致快速输入时卡顿,这是因为筛选任务是 同步更新,阻塞了渲染

import React, { useState, useTransition } from 'react';
 
function SearchComponent({ data }) {
  const [query, setQuery] = useState('');
  const [filteredData, setFilteredData] = useState(data);
  const [isPending, startTransition] = useTransition();
 
  const handleChange = (event) => {
    const value = event.target.value;
    setQuery(value);
 
    startTransition(() => {
      // 将筛选操作标记为低优先级任务
      const filtered = data.filter(item =>
        item.toLowerCase().includes(value.toLowerCase())
      );
      setFilteredData(filtered);
    });
  };
 
  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={handleChange}
        placeholder="Search..."
      />
      {isPending && <div>Loading...</div>}
      <ul>
        {filteredData.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

场景二:一个 Tab 栏,Tab 栏所对应的内容会根据选择的 Tab 执行图表的渲染,在快速切换 Tab的时候,会感觉到明显的卡顿,使用 useTransition 可以优化这种情况

import React, { useState, useTransition } from 'react';
 
function TabComponent({ fetchDataForTab }) {
  const [activeTab, setActiveTab] = useState(0);
  const [tabContent, setTabContent] = useState(null);
  const [isPending, startTransition] = useTransition();
 
  const handleTabChange = (newTab) => {
    setActiveTab(newTab);
 
    // 使用 useTransition 将数据请求和图表渲染标记为低优先级
    startTransition(() => {
      fetchDataForTab(newTab).then(data => {
        setTabContent(data);
        // 在这里可以触发图表渲染逻辑,例如 setChartData(data);
      });
    });
  };
 
  return (
    <div>
      <div className="tab-bar">
        {[0, 1, 2].map(tab => (
          <button
            key={tab}
            onClick={() => handleTabChange(tab)}
            style={{ fontWeight: tab === activeTab ? 'bold' : 'normal' }}
          >
            Tab {tab + 1}
          </button>
        ))}
      </div>
      {isPending && <div>Loading tab content...</div>}
      <div className="tab-content">
        {/* 这里可以放置图表组件或其他渲染的内容 */}
        {tabContent ? <ComplexChart data={tabContent} /> : <div>No content</div>}
      </div>
    </div>
  );
}
 
function ComplexChart({ data }) {
  // 假设这是一个复杂的图表渲染组件
  return <div>Rendering chart with data...</div>;
}
  • tab 栏切换立即生效:由于 setActiveTab 是高优先级的,tab 切换时的视觉反馈会迅速响应。
  • 延迟的内容加载:startTransition 包裹的数据请求和复杂渲染逻辑作为低优先级任务执行,React 会在空闲时处理这些任务,保证界面的流畅度。
  • 加载指示:isPending 在过渡进行时为 true,可以用来显示加载提示,提醒用户数据和渲染正在进行。

Reference

双链

React Hooks CheatSheet