IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React 18 新特性 -> 正文阅读

[JavaScript知识库]React 18 新特性

这里介绍一下React18的4个新特性:

  • Automatic batching
  • Concurrent APIs
  • SSR for Suspense
  • New Render API

Automatic bacthing

在 React 中使用setState来进行dispatch组件的State变化,当setState在组件中被调用后,并不会立即触发重新渲染。React 会执行全部事件处理函数,然后触发一个单独的re-render,合并所有的更新。
比如在点击+1的例子中,如果方法里连续触发三次setState,最终React会将更新函数放到一个队列里,然后合并队列触发setState的re-render,这就是batching的含义。

这样既可以减少程序数据状态存在中间值导致的不稳定性,也可以提高渲染性能。

在React 18 之前,如果在回调函数的异步调用中,执行setState,由于丢失上下文,无法做合并处理,所以每次setState调用都会触发一次re-render。

function handleClick() {
	// React 18 之前的版本
	(/*...*/).then(() => {
		setCount(c => c + 1); // 立刻重新渲染
		setShow(show => !show); // 立刻重新渲染
	});
}

React 18中,任何情况下都可以合并渲染!
如果仍然希望setState之后立即重新渲染,只需要使用flushSync包裹。

function handleClick() {
	// React 18
	fecth(/*...*/).then(() => {
		ReactDOM.flushSync(() => {
			setCount(c => c + 1); // 立刻重新渲染
			setFlag(f => !f);
		})
	})
}

Automatic batching 机制让我们有能力对渲染顺序和节奏进行一些基础的把控。例如在Canvas画布编辑场景中,我们可以加载完主节点框架之后立刻进行渲染,而每个节点的内容则可以进行合并渲染,尽可能加快用户看到可编辑页面的时间,同时避免http异步函数引起的频繁渲染的性能开销。

Concurrent APIs

官方明确指出了React 18 中并不存在 Concurrent Mode,只有用于并发渲染的并发新特性,开发者希望能够在Web Platform引入并发渲染,来实现多个渲染任务的并行渲染,其中Suspense就是基于此诞生的。

React18支持并发特性的三个API

  • startTransition()
  • useDeferredValue()
  • useTransition()

startTransition()

import { startTransition } from 'react';

// 紧急更新
setInputValue(input)

// 标记回调函数内的更新为 非紧急更新
startTransition(() => {
	setSearchQuery(input)
})

所以,startTransition的作用就是:被startTransition包裹的setState触发的渲染被标记为不紧急渲染,意味着它们可以被其他紧急渲染所抢占,这种渲染优先级的调整手段可以帮助我们解决各种性能伪瓶颈,提升用户体验。

useDeferredValue()

这个hook适用于设置延迟值

function Page() {
	const [filters, mergeFilter] = useMergeState(defaultFilters);
	const deferedFilters = React.useDeferredValue(filters);
	
	return (
		<>
			<Filters filters={filters} />
			<List filters={deferedFilters}>
		</>
	)
}

useDeferredValue() 会将List组件的渲染变得更加平滑,深层次看来是 defered value 引起的渲染会被标记为不紧急渲染,会被filters引起的渲染进行抢占,进而达到用户快速输入搜索等场景下页面抖动或卡顿问题。

SSR for Suspense

早在2018年,React就推出了Suspense的基础版本。可以在客户端配合React.lazy动态加载代码,实现数据拉取和状态控制的关注点分离(即当子组件未加载完成时,父组件填充fallback声明的组件),但是不能在服务器端进行加载。

<Suspense fallback={<Loading />}>
	<Header />
	<Suspense fallback={<ListPlaceholder />}>
		<ListLayout />
	</Suspense>
</Suspense>

在React18中,Suspense可以运行在服务器端,Server Rendering的性能不再受制于性能最差的组件(木桶效应)。
在React 18 之前,Server Rendering的流程就是服务端请求所有数据,然后发送HTML到客户端或者说浏览器,然后由客户端的hydrate内容(可以搜索同构渲染进行学习),每个环节必须按部就班的执行。当Suspense可以在服务器端使用之后,一旦某个组件加载慢,就可以将fallback的内容传输到客户端(例如loading态),保证用户可以尽可能早的可进行交互。
更加优秀的是,hydrate可以通过用户的行为来调整优先级。例如Profile组件和正在Loading的组件同时处于Suspense的流程中,此时用户点击评论组件,React将会优先hydrate评论组件,尽可能优先满足用户交互体验。
回归到代码实现细节,整体框架上服务器和客户端的连接必然趋向于持续性的长连接,因此res.send需要变为res.socket,pipeToNodeWritable替换renderToString并配合Suspense即可。

New Render API

新的更友好的语义化render方式。

const container = document.getElementById('app');

// 旧的render API
ReactDOM.render(<App />, container);

// 新的 createRoot API
const root = ReactDOM.createRoot(container);
root.render(<App />);

Client 端提供了 新 水合 Hydrate API

const root = ReactDOM.createRoot(container, <App tab="home" />)

以及新的 useId() API来为组件生成唯一ID。

由于Suspense和并发渲染在React 18的大规模使用,一些具有External stores的API比如全局变量、document对象如何在并发场景下保持一致性呢?
React 18 提供了useSyncExternalStore这个hook,来保证External stores的一致性。

useSyncExternalStore(
	// 注册回调函数
	subscribe: (callback) => Unsubscribe,
	// 获取快照函数
	getSnapshot: () => state
) => state

具体使用方式例子:

const store = {
	state: { count: 0 },
	setState: (fn) => {
		store.state = fn(store.state); // 需要不可变的更新
		store.listeners.forEach(listener => listender());
	},
	listeners: new Set(),
	subscribe: (callback) => {
		store.listeners.add(callback);
		return () => store.listeners.delete(callback);
	},
	getSnapshot: () => {
		const snap = Object.freeze(store.state);
		return snap;
	}
}

// use external store
const Component = () => {
	const snap = useSyncExternalStore(stor.subscribe, store.getSnapshot);
	return <div>{snap.count}</div>
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 23:16:14  更:2022-04-01 23:16:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:39:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码