一块儿来看 React 18 最新特性

React 18 Alpha 以及来了,并无像 React 17 没有更新不少新特性,V18 做为 React 的下一个大版本将关注点放在了并发模式上也就是谈论了好久的(Concurrent Mode)javascript

那么究竟都将有哪些新特性,下面让咱们一块儿来看一看。css

安装 React 18 Alpha

npm install react@alpha react-dom@alpha
复制代码

新的 Root API

以前的使用中都是经过 ReactDom.render 将应用组件渲染到页面的根元素html

ReactDOM.render(<APP/>,document.getElementById( root ))
复制代码

React 18 提供了新的方法 经过 ReactDom.creatRoot 建立根节点对象,在经过根节点对象进行渲染。java

(使用 CodeSandBox 进行测试)react

// index.js
import { StrictMode } from "react";
import ReactDOM from "react-dom";

import App from "./App";

const rootElement = document.getElementById("root");
const root = ReactDOM.createRoot(rootElement);
root.render(
  <StrictMode> <App />{" "} </StrictMode>
);
复制代码

节点自动批量重渲染

在React 17及更早版本中,当浏览器事件触发组件批量状态更新从而渲染更新时,React 不会自动将组件批量从新渲染。git

可是若是使用上面提到的 V18 新 Root API,则全部状态更新都将在发生时自动批量重渲染。github

若是某些关键组件不想被自动更新可使用 ReactDOM.flushSync() 退出操做npm

import { flushSync } from 'react-dom'; // Note: react-dom, not react

function handleClick() {
  flushSync(() => {
    setCounter(c => c + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setFlag(f => !f);
  });
  // React has updated the DOM by now
}

复制代码

新的 Suspense 容器组件

React 18 的更新后全面支持 Suspense ,顾名思义将暂时闲置的组件搁置起来,实现懒加载。浏览器

import "./styles.css";
import { useEffect, useState, useLayoutEffect, Suspense } from "react";
import { fetchProfileData } from "./fakeApi";

const initialResource = fetchProfileData();

function ProfilePage() {
  const [resource, setResource] = useState(initialResource);
  return (
    <> <Suspense fallback={ <> <h1>Loading profile...</h1> </> } > <Sibling name="one" /> <ProfileDetails resource={resource} /> <Suspense fallback={<h1>Loading posts...</h1>}> <Sibling name="two" /> <ProfileTimeline resource={resource} /> <Sibling name="three" /> </Suspense> <Sibling name="four" /> </Suspense> </>
  );
}

function Sibling({ name }) {
  useLayoutEffect(() => {
    console.log("Layout effect Sibling", name);
    return () => {
      console.log("Layout cleanup Sibling", name);
    };
  });

  useEffect(() => {
    console.log("Effect Sibling", name);

    return () => {
      console.log("Cleanup Sibling", name);
    };
  }, [name]);

  console.log("Render sibling", name);
  return <h1>Sibling</h1>;
}

function ProfileDetails({ resource }) {
  useLayoutEffect(() => {
    console.log("Layout effect ProfileDetails");
    return () => {
      console.log("Layout cleanup ProfileDetails");
    };
  });

  useEffect(() => {
    console.log("Effect ProfileDetails");
    return () => {
      console.log("Cleanup ProfileDetails");
    };
  });
  const user = resource.user.read();
  return <h1>{user.name}</h1>;
}

function ProfileTimeline({ resource }) {
  const posts = resource.posts.read();
  useLayoutEffect(() => {
    console.log("Layout effect ProfileTimeline");
    return () => {
      console.log("Layout cleanup ProfileTimeline");
    };
  });

  useEffect(() => {
    console.log("Effect ProfileTimeline");
    return () => {
      console.log("Cleanup ProfileTimeline");
    };
  });

  return (
    <ul> {posts.map((post) => ( <li key={post.id}>{post.text}</li> ))} </ul>
  );
}

export default ProfilePage;

复制代码

当数据未加载完成,显示 Loading 组件,加载后显示完整组件。markdown

代码源于romantic-architecture-ht3qi

关于 Suspense API 也还没有稳定,不建议使用在生产环境

Suspense List

Suspense List 为 Concurrent Mode 中的提案 reactjs.org/docs/concur…

Suspense List 做为 Suspense 的容器组件经过编排这些组件向用户显示的顺序,帮助协调许多能够挂起的组件。

<SuspenseList revealOrder="forwards">
  <Suspense fallback={'Loading...'}> <ProfilePicture id={1} /> </Suspense>
  <Suspense fallback={'Loading...'}> <ProfilePicture id={2} /> </Suspense>
  <Suspense fallback={'Loading...'}> <ProfilePicture id={3} /> </Suspense>
  ...
</SuspenseList>
复制代码
  • revealOrder (forwards, backwards, together) 定义了 SuspenseList 子组件应该显示的顺序。

  • tail (collapsed, hidden) 指定如何显示 SuspenseList 中未加载的项目。

  • 默认状况下,SuspenseList 将显示列表中的全部 fallback。

  • collapsed 仅显示列表中下一个 fallback。hidden 未加载的项目不显示任何信息。

  • 请注意,SuspenseList 只对其下方最近的 Suspense 和 SuspenseList 组件进行操做。它不会搜索深度超过一级的边界。不过,能够将多个 SuspenseList 组件相互嵌套来构建栅格。

startTransition API

这是 V18 引入的新 API,这有助于保持当前的网页响应,而且可以同时进行计算量大复杂度高的的非阻塞UI更新。 之前咱们可能会本身去加一些防抖这样的操做去人为的延迟过滤数据的计算和渲染。新的 startTransition API 可让咱们把响应数据标记成 transitions 状态延迟处理。

官方工做组两个应用场景提出了:

  • 慢速渲染:React 须要执行大量计算,以便过渡UI来显示结果。(如搜索引擎的关键词联想)
  • 慢速网络:React 正在等待来自网络的某些数据。这种用例与 Suspense 紧密集成。(懒加载)

startTransition API 可让开发者显式的指定那个UI渲染的优先级更高,哪些须要实时更新哪些须要延迟更新

(使用 CodeSandBox 进行测试)

// APP.js
import "./styles.css";
import { useState, startTransition } from "react";

export default function App() {
  let [value, setValue] = useState(0);

  const onChange = (event) => {
    startTransition(() => {
      setValue(event.target.value);
      console.log(event.target.value);
    });
  };

  return (
    <div className="App"> <input value={value} onChange={onChange} /> <div>{value}</div> </div>
  );
}

复制代码

全部在 startTransition 回调中的更新都会被认为是非紧急处理,若是出现更紧急的更新(好比用户又输入了新的值),则上面的更新都会被中断,直到没有其余紧急操做以后才会去继续执行更新。

实际测试时发现好像对于中文输入法不是特别友好但目前没有找到合适的解决方案。

useDeferredValue

useDeferredValue 容许变量延迟更新, API 还未稳定,当前用法为

import "./styles.css";
import { useState, useDeferredValue } from "react";

export default function App() {
  let [value, setValue] = useState(0);
  const deferredValue = useDeferredValue(value, { timeoutMs: 2000 });

  return (
    <div className="App"> <div>{deferredValue}</div> <button onClick={()=>{setValue(deferredValue+1)}}>click me</button> </div>
  );
}

复制代码

总结

React 18 发布计划 React 18 官方介绍(github.com/reactwg/rea… API useDeferredValue、 还没 released ,咱们下次再用,下面是 React 18 的发布时间表:

  • React 18 Alpha 版本:如今就能用
  • 公开的 Beta 版:至少在 Alpha 版本后的几个月
  • RC 版本:至少在 Beta 版发布后的几周
  • 正式版:至少在 RC 版本发布以后的几周

参考连接:

Everything New in React 18

【第一批吃螃蟹】试用 React 18 !

解读官方博客:React18真的来了

相关文章
相关标签/搜索