一塊兒來看 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真的來了

相關文章
相關標籤/搜索