官方警告,react18已經來了


18他來了

什么,react18都來啦,不敢相信,react17都還沒捂熱,18突然就來了,沒有一點點防備,就是這么驚喜,react官網已經放出react18的介紹了,還是不信的話,你點點鏈接瞧瞧官宣介紹吧。看日子是8號發布的,大致瞄了一眼,我就趕緊去npm搜一下版本,18.0.0-alpha已經在11個小時之前放上去了。現在只是嘗鮮版本,根據官方介紹,18正式版本推出之前,還會有數月的打磨,要在工作中要用到還需要耐心等待,但是對於react技術棧的同學來說,還是要乘早關注起來,如果能加入社區提供一些正向的反饋,那更是極好的。說了這么多,我們接下來看下官方多react18的介紹吧。

新特新

1.Automatic batching

這個特性簡單來說,就是自動批量更新,對於熟悉react的同學來說,對於下面這段代碼的渲染執行一定不會陌生:

function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    setCount(c => c + 1); // Does not re-render yet
    setFlag(f => !f); // Does not re-render yet
    // React will only re-render once at the end (that's batching!)
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}

這段代碼我直接拷貝Dan Abramov對於Automatic batching特性說明的演示代碼(下面也是-_-),從注釋來看,handleClick只會觸發一次渲染,為什么這么設計呢,用Dan的例子解釋:飯店的服務生不會你點了一個菜就會去通知廚房吧,而是點完了之后再一次性告訴廚房,這么做的一個最大好處就是性能更好,接下來再看下一段代碼:

function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    fetchSomething().then(() => {
      // React 17 and earlier does NOT batch these:
      setCount(c => c + 1); // Causes a re-render
      setFlag(f => !f); // Causes a re-render
    });
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}

這一次會渲染兩次,如果你深入react原理了解,也不會很差異這種結果。簡單來說,異步任務執行的時候其實已經不在react的上下文環境了,react內部是通過一個標識來標記是否需要批量更新的,render開始,標記為true,commit之后,標記為false,異步任務再執行,其實是在commit之后的,那么由於標記為false,因此就不走批量了。大概就是這么個意思,有興趣的可以去深挖一下其中的實現細節。不光是setTimeout,用dan的描述來說,Updates inside of promises, setTimeout, native event handlers, or any other event were not batched in React by default,因此promise/setTimeout/原生事件這些觸發的渲染都不會走批量,當然這些都是在18版本之前,18版本是怎樣的呢,還是上代碼吧:

setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
}, 1000);

這里的異步任務就完成了自動的批量更新,當然在18版本要開啟這個功能的話,需要使用ReactDOM.createRoot去掛載我們的應用,如果我們還是使用ReactDOM.render的話,就不會啟用Automatic batching了。
Automatic batching看起來很香,但是如果在一些場景我不想用呢,官方也提供了解決辦法,請看例子:

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
}

react work group還對Automatic batching做了很多的探討,包括對class/hooks的影響,有興趣的可以點擊這里查看

看完對Automatic batching的說明后,還想補充一點,react18版本前的blocking和concurrent模式其實已經支持Automatic batching of multiple setStates了,大家可以去試試效果。最后再說一下unstable_batchedUpdates這個api,在18版本之前,如果我們要手動批量,需要借助它去實現,在18版本會依然支持。

2.startTransition

這是一個嶄新的api,干什么的呢,就是讓我們的應用交互更加絲滑,用來提升體驗的,首先我們來了解一下它要解決一個什么樣的問題。

官方工作小組里面的討論描述了一個場景,就是一個輸入框,接收用戶輸入,然后去篩選列表項,場景很常見,但是會有一個性能隱患,輸入這個操作可能會觸發大量的更新,導致頁面卡頓,給用戶直觀的感受就是輸入框有點卡,不能實時顯示輸入的字符了,那么要怎么破呢,這讓我想到了react的並發渲染模式,不就是要來解決這種優先級的問題么,但是遺憾的是一直處於實驗當中,還不能安心用在工作中,不扯遠了,還是回到這個api上來,通過代碼我們對比一下:

// Urgent: Show what was typed
setInputValue(input);

// Not urgent: Show the results
setSearchQuery(input);
import { startTransition } from 'react';

// Urgent: Show what was typed
setInputValue(input);

// Mark any state updates inside as transitions
startTransition(() => {
  // Transition: Show the results
  setSearchQuery(input);
});

代碼片段1就是我們的常用寫法,用戶輸入就更新輸入框的狀態值進行實時顯示輸入,然后去篩選列表,setInputValue和setSearchQuery是同時執行的;代碼片段2就使用了startTransition這個api,將setSearchQuery包裹其中,實現手動的渲染任務優先級排列,那么此時setInputValue的更新就高於setSearchQuery,因此用戶的輸入響應就能得到保證,從而實現絲滑的體驗,官方還將其於setTimeout進行了對比,這里就不展開介紹了,大家點擊這里查看

3.New Suspense SSR Architecture

react18對SSR的性能進行了新的改進,引入了pipeToNodeWritable這個新的API,這個API可以替換renderToString,同時renderToNodeStream被標記為Deprecated,為什么會有這些改動呢,官方給出了解釋:

renderToString: Keeps working (with limited Suspense support).
renderToNodeStream: Deprecated (with full Suspense support, but without streaming).
pipeToNodeWritable: New and recommended (with full Suspense support and streaming)

出現了兩個需要注意的單詞:Suspense和streaming,Suspense這個組件在16.6.0被正式提出來,以前主要配合React.lazy用來異步加載組件的,而streaming就是指的React Server Components,現在react18對這兩者的支持就更加完善了,因此react18的SSR將讓用戶更快的看見界面,更早的交互。
react18的SSR相比以前的SSR,有啥優勢呢,那我們先看下傳統的SSR流程吧:

On the server, fetch data for the entire app.
Then, on the server, render the entire app to HTML and send it in the response.
Then, on the client, load the JavaScript code for the entire app.
Then, on the client, connect the JavaScript logic to the server-generated HTML for the entire app (this is “hydration”).

以上四步必須嚴格按照流程一步步來,就像waterfall一樣,如果其中哪一步慢了,就會阻塞后面的流程,這樣用戶就需要忍受更長的白屏時間,因此如果將上面四個步驟打散成一個個小的任務單元,那么先完成的任務就可以盡快呈現到用戶面前,這樣體驗自然就更優了,這也是react18對Suspense和streaming改進的動力所在,dan對這一部分有詳細的介紹,點這里了解更多。

漸進式升級

每當版本發生了重大更新,升級就是每個框架必須要考慮的一件事情,對於開發者來講,升級不能對我現有的項目造成影響吧,放心,react考慮得比我們更多,其實vue也是一樣,都提供了漸進式平滑得升級策略。react官方說了,放心升級吧,只需對應用程序代碼進行很少的更改或不做任何更改,其實不光是react18,react16到17,對於升級其實都是成本很小的。

社區和react18工作小組

React 18 Working Group也是隨着react18版本的到來而成立的一個組織,工作職能跟w3c的working group類似,作為聯系社區與react18的橋梁,充分吸收來自各方的意見和討論,大家有興趣可以去了解一下。

發布計划

React 18 Library Alpha (Available now)
React 18 Public Beta (Months)
React 18 RC (Months)
React 18 (2-4 weeks after RC)

官方推出的發布計划,大家拭目以待吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM