React 18 Alpha 以及來了,並無像 React 17 沒有更新不少新特性,V18 做爲 React 的下一個大版本將關注點放在了併發模式上也就是談論了好久的(Concurrent Mode)javascript
那麼究竟都將有哪些新特性,下面讓咱們一塊兒來看一看。css
npm install react@alpha react-dom@alpha
複製代碼
以前的使用中都是經過 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
}
複製代碼
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 爲 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 組件相互嵌套來構建柵格。
這是 V18 引入的新 API,這有助於保持當前的網頁響應,而且可以同時進行計算量大複雜度高的的非阻塞UI更新。 之前咱們可能會本身去加一些防抖這樣的操做去人爲的延遲過濾數據的計算和渲染。新的 startTransition API 可讓咱們把響應數據標記成 transitions 狀態延遲處理。
官方工做組兩個應用場景提出了:
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 容許變量延遲更新, 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 的發佈時間表:
參考連接: