React18更新特性介绍

662 阅读4分钟

更新版本

2022年3 月 29 日,React 18.0.0 正式发布,截止到今天,更新到了18.2.0版本,最后一次更新是22年年底

特性1:Concurrent Mode

  Concurrent Mode指的是react的并发更新,在18版本前,react如果要执行更新,由于js是单线程语言,同一时间只能执行一个任务,因此react更新过程不可中断。如果react更新过程中有动画执行,就会出现掉帧的情况,如下图,只有更新完成之后才能执行其他任务事件回调。

在18版本之后,渲染模式发生了变化,也就是并发更新,在react更新过程中渲染可以被中断,如下图,在一帧执行内优先执行高优先级任务,执行完高优先级任务后如果一帧还有剩余时间,则执行react更新,如果剩余时间用完,则中断react更新,继续执行其他任务,以此内推,这样就实现了ract并发更新。(高优先级任务有:用户输入响应、动画执行等)

问题:react16版本已引入了fiber架构,Concurrent Mode和fiber一样啊,没看出有什么区别

答:虽然 React 16 的核心工作全部都是在 fiber架构上,但是这并不代表 Concurrent Mode 已经可以稳定使用了,React 16 做的这些所有的工作只是让 Concurrent Mode 成为可能,并且在 Concurrent Mode 下做了一些小小的尝试,在 16 、17版本默认仍然是采用同步渲染的模式。

特性2:useTransition

useTransition是伴随并发更新推出的,使用useTransition可以降低任务的优先级,从而从高优先级任务先执行。以下代码是useTransition的例子,降低了搜索结果的优先级,让用户输入先执行,避免出现卡顿现象。之前为了避免出现卡顿现象,我们使用函数防抖功能,现在使用useTransition体验会更好。

      import { useState, useTransition } from "react";

      const Demo = () => {
        const [value, setInputValue] = useState("");
        const [query, setSearchQuery] = useState("");
        const [isPending, startTransition] = useTransition();
        const handleChange = (e) => {
          setInputValue(e.target.value);
          startTransition(() => {
            setSearchQuery(e.target.value);
          });
        };
        return (
          <div>
            {isPending && <span>isTransiton</span>}
            <input
              onChange={handleChange}
              placeholder="输入搜索内容"
              value={value}
            />
            <NewList query={query} />
          </div>
        );
      };

特性3:useDeferredValue

useDeferredValue与useTransition很像,都是为了降低任务的优先级,只不过useDeferredValue是在值的渲染阶段降低,而useTransition是在值的设置阶段降低,useDeferredValue还可以设置延迟渲染的时间,例如:const deferredText = useDeferredValue(text, {timeoutMs: 2000 }

      import { useState, useDeferredValue } from "react";

      const Demo = () => {
        const [value, setInputValue] = React.useState("");
        const query = useDeferredValue(value);
        const handleChange = (e) => {
          setInputValue(e.target.value);
        };
        return;
        <div>
          <button>useDeferredValue</button>
          <input
            onChange={handleChange}
            placeholder="输入搜索内容"
            value={value}
          />
          <NewList query={query} />
        </div>;
      };

特性4:useSyncExternalStore

以前只有state、props、context触发react更新,外部状态改变无法触发更新,有了useSyncExternalStore后,可以通过它订阅外部状态,从而使react触发更新,以下是一个网络状态改变时触发react更新的例子。

export function useOnlineStatus() {
  const isOnline = useSyncExternalStore(subscribe, getSnapshot);
  return isOnline;
}

function getSnapshot() {
  return navigator.onLine;
}

function subscribe(callback) {
  window.addEventListener("online", callback);
  window.addEventListener("offline", callback);
  return () => {
    window.removeEventListener("online", callback);
    window.removeEventListener("offline", callback);
  };
}

function ChatIndicator() {
  const isOnline = useOnlineStatus();
  // ...
}

特性5:自动批处理

批处理是指,当 React 在一个单独的重渲染事件中批量处理多个状态更新以此实现优化性能。如果没有自动批处理的话,我们仅能够在 React 事件处理程序中批量更新。在 React 18 之前,默认情况下 promisesetTimeout、原生应用的事件处理程序以及任何其他事件中的更新都不会被批量处理;但现在,这些更新内容都会被自动批处理:

// 以前: 只有 React 事件会被批处理。
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React 会渲染两次,每次更新一个状态(没有批处理)
}, 1000);

// 现在: 超时,promise,本机事件处理程序
// 原生应用时间处理程序或者任何其他时间都被批处理了
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // 最终,React 将仅会重新渲染一次(这就是批处理!)
}, 1000);

特性6:服务端组件(实验性)

React Server Component简称RSC ,主要目的是在服务端获取接口数据或数据库数据,提升性能。通常RCC(客户端组件)我们请求数据是在useEffect中,此时组件已经渲染过一次,请求完数据,又再渲染一次,过程比较繁琐。RSC的出现改变了这个现状,数据请求直接在RSC中处理,再通过SSR渲染,浏览器只需负责下载和渲染html页面,如下图。目前next13已经实现了服务端组件,性能对比next12得到了极大提升。

与SSR、SSG的区别

SSR:服务端渲染,输出产物是HTML,浏览器可以直接解析,

SSG:静态渲染,也就是部署阶段渲染,输出产物也是HTML

RSC:会流式输出一种类JSON的数据结构,由前端的React相关插件解析