Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React - useTransition #56

Open
jtwang7 opened this issue Nov 7, 2022 · 0 comments
Open

React - useTransition #56

jtwang7 opened this issue Nov 7, 2022 · 0 comments

Comments

@jtwang7
Copy link
Owner

jtwang7 commented Nov 7, 2022

React - useTransition

转载文章:

🤓 仅供学习使用,后续会添加个人理解

在Web应用中,UI更新(比如在输入框中输入字段,从下拉框选择一个值)的优先级应该高一些,而其他操作(比如显示列表过滤内容)优先级要低一些。从React 18(2021.06发布了alpha版本)开始,我们就可以开启并发模式-concurrent,concurrent模式允许将UI更新标记为高优先级的或者可中断的低优先级操作。在这篇文章中,你会掌握如何使用useTransition()将UI更新标记为低优先级,这种操作对大量的非紧急更新非常有用。

useTransition 钩子

默认情况下,我们认为React中的所有更新都是紧急的(也就是所有更新的优先级相同)。那会导致一个问题-快速更新会被大量更新拖慢速度。然而,从React 18中新增特性-concurrency之后,你就可以将某些更新标记为可中断的和非紧急的-也就是所谓的transitions。这种新特性在大量的UI更新操作中尤其有效,比如过滤一个较大的列表。
❇️ useTransition 这个钩子函数使得用户能够在React组件中使用concurrent模式特性:
调用 const [isPending, startTransition] = useTransitionHook() 返回一个具有两个成员的数组:

  • isPending: 指明这个transition正在加载中(pending)
  • startTransition(回调): 允许用户将回调中的任何UI更新标记为transitions.
import { useTransition } from 'react';
function MyComponent() {
    const [isPending, startTransition] = useTransition();
    // ...
    const someEventHandler = (event) => {
        startTransition(() => {
            // Mark updates as transitions
            setValue(event.target.value);
        });
    }

    return <HeavyComponent value={value} />;
}

紧急的大量UI更新

接下来考虑一个所有更新都很紧急的例子,以及这些大量更新是如何影响用户体验的。
比如有一个员工名字列表和一个查找员工的姓名搜索框,这个组件会高亮显示匹配搜索内容的员工姓名。
以下是可能实现的代码:

import { useState } from 'react';
export function FilterList({ names }) {
  const [query, setQuery] = useState('');
  const changeHandler = ({ target: { value } }) => setQuery(value);

  return (
    <div>
      <input onChange={changeHandler} value={query} type="text" />
      {names.map((name, i) => (
        <ListItem key={i} name={name} highlight={query} />
      ))}
    </div>
  );
}
function ListItem({ name, highlight }) {
  const index = name.toLowerCase().indexOf(highlight.toLowerCase());
  if (index === -1) {
    return <div>{name}</div>;
  }
  return (
    <div>
      {name.slice(0, index)}
      <span className="highlight">
        {name.slice(index, index + highlight.length)}
      </span>
      {name.slice(index + highlight.length)}
    </div>
  );
}

在组件内部,query是包含查询字符串的状态变量。输入框是一个控制组件-用于在用户输入改变时更新query状态变量。当使用者在快速在输入框内键入查询字段,你可能会注意到键入延迟以及用户界面在明显的时间内没有响应。
👉 为什么会出现这种现象,如何解决呢?
在用户键入时更新输入框的值是一个必须快速执行的紧急任务,更新高亮显示匹配列表是一个繁重且不紧急的任务。大量的非紧急任务落后于轻量的紧急任务。useTransition()钩子能够帮助你区分紧急的UI更新和非紧急的UI更新。

大量的UI更新作为过渡(transitions)

之前已经提高了,你可以使用 useTransition 告诉React哪些UI更新是紧急的(比如更新输入框的值)和哪些UI更新是不紧急的transitions(比如更新高亮匹配查询内容的姓名列表)
💡 我们来对FilterList组件做一下必要的调整:
首先,我们调用 [isPending, startTransition] = useTransition() 钩子来访问startTransition()函数,然后专门这个transition创建了一个保存状态的状态变量。

import React, { useState, useTransition } from "react";

export function FilterList({ names }) {
  const [query, setQuery] = useState("");
  const [highlight, setHighlight] = useState("");

  const [isPending, startTransition] = useTransition();

  const changeHandler = ({ target: { value } }) => {
    setQuery(value);
    startTransition(() => setHighlight(value));
  };

  return (
    <div>
      <input onChange={changeHandler} value={query} type="text" />
      {isPending ? 'pending' : (
        names.map((name, i) => (
          <ListItem key={i} name={name} highlight={highlight} />
        ))
      )}
    </div>
  );
}

function ListItem({ name, highlight }) {
  const index = name.toLowerCase().indexOf(highlight.toLowerCase());
  if (index === -1) {
    return <div>{name}</div>;
  }
  return (
    <div>
      {name.slice(0, index)}
      <span className="highlight">
        {name.slice(index, index + highlight.length)}
      </span>
      {name.slice(index + highlight.length)}
    </div>
  );
}

使用了transitionos特性,如果你非常快速地在输入框中键入,你会注意到高亮列表的延迟更新。
React将紧急任务(当用户键入时更新输入框)的更新和非紧急任务(高亮显示过滤内容)的渲染区分开了,这样的操作提升了用户体验。

总结

React中的并发模式(concurrent mode)将紧急任务和非紧急任务区分开,使UI更新更加人性化。在开启React 18并发模式新特性之后,你可以使用useTransition()钩子进而使用startTransition(callback)函数。
useTransition()使你能够将默写更新标记为过渡(transitions):

const [isPending, startTransition] = useTransition();
startTransition(() => {
  // Mark updates as transitions
  setStateValue(newValue);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant