react-16版本新特性

一、hooks

import { useState } from 'react'function App() {// 参数:状态初始值比如,传入 0 表示该状态的初始值为 0// 返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)const [count, setCount] = useState(0)return (<button onClick={() => { setCount(count + 1) }}>{count}</button>)
}
export default App

二、memo、lazy、Suspense

import React, { Suspense } from 'react';const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {return (<div><Suspense fallback={<div>Loading...</div>}><OtherComponent /></Suspense></div>);
}

三、Profiler

Profiler 能添加在 React 树中的任何地方来测量树中这部分渲染所带来的开销

function onRenderCallback(id, // 发生提交的 Profiler 树的 “id”phase, // "mount" (如果组件树刚加载) 或者 "update" (如果它重渲染了)之一actualDuration, // 本次更新 committed 花费的渲染时间baseDuration, // 估计不使用 memoization 的情况下渲染整棵子树需要的时间startTime, // 本次更新中 React 开始渲染的时间commitTime, // 本次更新中 React committed 的时间interactions // 属于本次更新的 interactions 的集合
) {// 合计或记录渲染时间。。console.log(id, // 发生提交的 Profiler 树的 “id”phase, // "mount" (如果组件树刚加载) 或者 "update" (如果它重渲染了)之一actualDuration, // 本次更新 committed 花费的渲染时间baseDuration, // 估计不使用 memoization 的情况下渲染整棵子树需要的时间startTime, // 本次更新中 React 开始渲染的时间commitTime, // 本次更新中 React committed 的时间interactions // 属于本次更新的 interactions 的集合);
}
//Navigation update 0 0 57313.90000009537 57314.5 Set(0) {size: 0}<Profiler id="Navigation" onRender={onRenderCallback}><divonClick={() => {setNumber((e) => e + 1);}}>test</div>
</Profiler>

四、createContext、createRef、forwardRef、生命周期函数的更新、Strict Mode

// 父组件中
const ThemeContext = React.createContext("light");const ParentComponent = () => {const inputRef = createRef();return (<ThemeContext.Provider value="dark"><ChildComponent ref={inputRef} /><buttononClick={() => {inputRef.current.focus();}}>获取焦点</button></ThemeContext.Provider>);
}//子组件
const ChildComponent = forwardRef((props, inputRef) => {const value = useContext(ThemeContext);return (<><input id="input" type="text" ref={inputRef} /><buttonstyle={{ background: "yellow" }}onClick={() => {console.log(value);}}>测试</button></>);
});

五、Fragment

<React.Fragment><ChildA /><ChildB /><ChildC />
</React.Fragment>

六、createPortal

ReactDOM.createPortal(child, container)

react-17版本新特性

一、全新的 JSX 转换

React 17以前,React中如果使用JSX,则必须像下面这样导入React,否则会报错,这是因为旧的 JSX 转换会把 JSX 转换为 React.createElement(…) 调用。

import React from 'react';
export default function App(props) {return <div>app </div>;
}

二、事件委托的变更

在 React 16 或更早版本中,React 会由于事件委托对大多数事件执行 document.addEventListener()。但是一旦你想要局部使用React,那么React中的事件会影响全局,当把React和jQuery一起使用,那么当点击input的时候,document上和React不相关的事件也会被触发,这符合React的预期,但是并不符合用户的预期。

React React17不再将事件添加在document上,而是添加到渲染 React 树的根 DOM 容器中:

const rootNode = document.getElementById('root');
ReactDOM.render(<App />, rootNode);

三、事件系统相关更改

除了事件委托这种比较大的更改,事件系统上还发生了一些小的更改,与以往不同,React 17中onScroll 事件不再冒泡,以防止出现常见的混淆 。

React 的 onFocus 和 onBlur 事件已在底层切换为原生的 focusin 和 focusout 事件。它们更接近 React 现有行为,有时还会提供额外的信息。

捕获事件(例如,onClickCapture)现在使用的是实际浏览器中的捕获监听器。这些更改会使 React 与浏览器行为更接近,并提高了互操作性。

注意:尽管 React 17 底层已将 onFocus 事件从 focus 切换为 focusin,但请注意,这并未影响冒泡行为。在 React 中,onFocus 事件总是冒泡的,在 React 17 中会继续保持,因为通常它是一个更有用的默认值。请参阅 sandbox ,以了解为不同特定用例添加不同检查。

四、去除事件池

在React 17 以前,如果想要用异步的方式使用事件e,则必须先调用调用 e.persist() 才可以,这是因为 React 在旧浏览器中重用了不同事件的事件对象,以提高性能,并将所有事件字段在它们之前设置为 null。如下面的例子:

function FunctionComponent(props) {const [val, setVal] = useState("");const handleChange = e => {// setVal(e.target.value);// React 17以前,如果想用异步的方式使用事件e,必须要加上下面的e.persist()才可以// e.persist();// setVal(data => e.target.value);};return (<div className="border"><input type="text" value={val} onChange={handleChange} /></div>);
}

但是这种使用方式有点抽象,经常会让对React不太熟悉的开发者懵掉,但是值得开心的是,React 17 中移除了 “event pooling(事件池)“,因为以前加入事件池的概念是为了提升旧浏览器的性能,对于现代浏览器来说,已经不需要了。因此,上面的代码中不使用e.persist();也能达到预期效果。

五、副作用清理时间

React 17以前,当组件被卸载时,useEffect和useLayoutEffect的清理函数都是同步运行,但是对于大型应用程序来说,这不是理想选择,因为同步会减缓屏幕的过渡(例如,切换标签),因此React 17中的useEffect的清理函数异步执行,也就是说如果要卸载组件,则清理会在屏幕更新后运行。如果你某些情况下你仍然希望依靠同步执行,可以用 useLayoutEffect。

当然React 17中的useEffect的清理函数异步执行之后,有一个隐患:

useEffect(() => {someRef.current.someSetupMethod();return () => {someRef.current.someCleanupMethod();};
});

问题在于 someRef.current 是可变的,因此在运行清除函数时,它可能已经设置为 null。解决方案是在副作用内部存储会发生变化的值:

useEffect(() => {const instance = someRef.current;instance.someSetupMethod();return () => {instance.someCleanupMethod();};
});

我们不希望此问题对大家造成影响,我们提供了 eslint-plugin-react-hooks/exhaustive-deps 的 lint 规则(请确保在项目中使用它)会对此情况发出警告。

六、返回一致的 undefined 错误

在 React 16 及更早版本中,返回 undefined 始终是一个错误,当然这是React的预期,但是由于编码错误 ,forwardRefmemo 组件的返回值是undefined的时候没有做为错误,React 17中修复了这个问题。React中要求对于不想进行任何渲染的时候返回 null

七、原生组件栈

在 React 17 中,使用了不同的机制生成组件调用栈,该机制会将它们与常规的原生 JavaScript 调用栈缝合在一起。这使得你可以在生产环境中获得完全符号化的 React 组件调用栈信息。

八、移除私有导出

React 17删除了一些以前暴露给其他项目的 React 内部组件。特别是,React Native for Web 过去常常依赖于事件系统的某些内部组件,但这种依赖关系很脆弱且经常被破坏。

在 React 17 中,这些私有导出已被移除。据我们所知,React Native for Web 是唯一使用它们的项目,它们已经完成了向不依赖那些私有导出函数的其他方法迁移。

九、启发式更新算法更新

React 16开始替换掉了Stack Reconciler,开始使用启发式算法架构的的Fiber Reconciler。那么为什么要发生这个改变呢?

React的killer feature: virtual dom

  • React15.x - Stack Reconciler
  • React16 - Fiber Reconciler
  • React17 - Fiber Reconciler (进阶版 - 优先级区间)

1、为什么需要fiber:对于大型项目,组件树会很大,这个时候递归遍历的成本就会很高,会造成主线程被持续占用,结果就是主线程上的布局、动画等周期性任务就无法立即得到处理,造成视觉上的卡顿,影响用户体验。

2、任务分解的意义:解决上面的问题

3、增量渲染(把渲染任务拆分成块,匀到多帧)

4、更新时能够暂停,终止,复用渲染任务

5、给不同类型的更新赋予优先级

6、并发方面新的基础能力

7、更流畅

React 17中更新了启发式更新算法,具体表现为曾经用于标记fiber节点更新优先级的expirationTime换成了为lanes,前者为普通数字,而后者则为32位的二进制,了解二进制运算的都比较熟悉了,这种二进制的lanes是可以指定几个优先级的,而不是像以前expirationTime只能标记一个。

之所以做这种改变,原因就是在于expirationTimes模型不能满足IO操作(Suspense),Suspense用法如下:

<React.Suspense fallback={<Loading />}><Content />
</React.Suspense>

react-18版本新特性

一、客户端渲染 API

带有 createRoot() 的 root API,替换现有的 render() 函数,提供更好的人体工程学并启用新的并发渲染特性。

import { createRoot } from "react-dom/client";
import { useState } from 'react'const App = () => {const [A, setA] = useState(1);const [B, setB] = useState(1);const handleClick = () => {setA((a) => a + 1);setB((b) => b - 1);};setTimeout(() => {setA((a) => a + 1);setB((b) => b - 1);}, 1000);return (<div><p>{A}</p><p>{B}</p></div>);
};const container = document.getElementById("app");
const root = createRoot(container);
root.render(<App />);root.unmount(); //卸载组件

如果你的项目使用了ssr服务端渲染,需要把ReactDOM.hydrate升级为ReactDOM.hydrateRoot

import { hydrateRoot } from "react-dom/client";const container = document.getElementById("app");
const root = hydrateRoot(container, <App tab="home" />);

在某些场景下 我们可能不需要批处理状态更新, 此时我们需要用到 react-dom 提供的flushSync函数, 该函数需传入一个回调, 并且会同步刷新回调中的状态更新

import { useState } from 'react'
import { flushSync } from 'react-dom'function App() {const [num1, setNum1] = useState(1)const [num2, setNum2] = useState(1)const add = () => {setTimeout(() => {flushSync(() => {setNum1((pre) => pre + 1)})flushSync(() => {setNum2((pre) => pre + 1)})})}console.log('渲染了')console.log(num1, num2)return (<div className="App"><header className="App-header">react 18</header><p>num1 : {num1}</p><p>num2 : {num2}</p><button onClick={add}>+1</button></div>)
}export default App

二、严格模式更新

React 18 带来了大把新特性,此外还有很多新特性正在路上。为了让你的代码为此做好准备,StrictMode 变得更加严格了。最重要的是,StrictMode 将测试组件对可重用状态的弹性,模拟一系列的挂载和卸载行为。它旨在让你的代码为即将推出的特性(可能以组件的形式)做好准备,这将在组件的挂载周期中保留这个状态。

虽然它肯定会在未来提供更好的性能,但就目前而言,启用 StrictMode 时必须要考虑这个事情。

除了以上提到的更改之外,根据你的 React 代码库,你可能还会发现其他一些更改。

值得一提的是,React 18 将不再支持 IE 浏览器,因为 React 18 现在依赖很多现代浏览器特性,如 Promise 或 Object.assign。

其余的更改与一些 React 行为的稳定性和一致性有关,不太可能影响你的代码库。

三、Transition

Transition 是由并发渲染提供支持的新特性之一。它旨在与现有状态管理 API 一起使用,以区分紧急和非紧急状态更新。通过这种方式,React 知道哪些更新需要优先考虑,哪些更新需要在后台通过并发渲染准备。

import { useTransition, useState } from "react";const App = () => {const [isPending, startTransition] = useTransition();const [value, setValue] = useState(0);function handleClick() {startTransition(() => {setValue((value) => value + 1);});}return (<div>{isPending && <Loader />}<button onClick={handleClick}>{value}</button></div>);
};

在 startTransition() 回调中提交的任何状态更新都将被标记为 transition,从而使其他更新具有优先权。如果你不能使用这个钩子,还有一个单独的 startTransition() 函数可用——虽然它不会通知你转换的进度。

import { startTransition } from "react";
// ...
startTransition(() => {// Transition updates
});
// ...

四、Suspense更新

在状态改变时,lazy() 加载的组件将触发 Suspense,导致 fallback 元素的渲染。如果你将状态更改标记为一个 transition,React 将知道它应该在后台准备新视图,同时仍保持当前视图可见。

import { Suspense, useTransition } from "react";const App = () => {const [value, setValue] = useState("a");const [isPending, startTransition] = useTransition();const handleClick = () => {startTransition(() => {setValue("b");});};return (<><Suspense fallback={<Loader />}><div style={{ opacity: isPending ? 0.7 : 1 }}>{value === "a" ? <A /> : <B />}</div></Suspense><Button onClick={handleClick}>B</Button></>);
};

React16、17、18版本新特性相关推荐

  1. Go 1.18 版本新特性详解!

    导语 | 本文推选自腾讯云开发者社区-[技思广益 · 腾讯技术人原创集]专栏.该专栏是腾讯云开发者社区为腾讯技术人与广泛开发者打造的分享交流窗口.栏目邀约腾讯技术人分享原创的技术积淀,与广泛开发者互启 ...

  2. Java9、10、11、12、13、14、15、16、17个版本新特性

    Java9新特性 1 模块化系统 模块(module)的概念,其实就是package外再裹一层,也就是说,用模块来管理各个package,通过声明某个package暴露,不声明默认就是隐藏.因此,模块 ...

  3. 一文总结Java\JDK 17发布的新特性

    简介: JDK 17已经于2021年3月16日如期发布.本文介绍JDK 17新特性.JDK 17于2021年9月14日正式发布(General-Availability Release).JDK 17 ...

  4. Oracle APEX 系列文章7:Oracle APEX 18.1 新特性

    引言 千呼万唤始出来, Oracle APEX 18.1 新版本终于发布了,还不了解 Oracle APEX 是什么的同学请移步这里: Oracle APEX 系列文章1:Oracle APEX, 让 ...

  5. 详解 Java 17中的新特性:“密封类”

    作者:程序猿DD 博客:https://blog.didispace.com/ Java 17推出的新特性Sealed Classes经历了2个Preview版本(JDK 15中的JEP 360.JD ...

  6. Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结...

    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结 1.1. Java的编年史2 ...

  7. iOS基础:新浪微博授权机制、 版本新特性

    文章目录 前言 1. 版本新特性 II. 新浪微博授权机制 2. 1.http://open.weibo.com/wiki/微博API 前言 新浪微博分享SDK 1. 版本新特性 HWNewFeatu ...

  8. Spark 3.2.0 版本新特性 push-based shuffle 论文详解(一)概要和介绍

    前言 本文隶属于专栏<大数据技术体系>,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见大数据技术体系 目录 Spark 3.2.0 ...

  9. Android Q(10.0 API29)版本新特性和兼容性适配

    摘要 1.本文档基于谷歌AndroidQ官方文档和一加Q版本应用兼容性整改指导 2.本文档主要对影响比较大的部分进行简单总结,内容并不全面: 3.版本号对应关系: Android-Q = Androi ...

最新文章

  1. 疯狂的消化之旅|消化系统简介
  2. window COM调试2[转]
  3. 代码流程图怎么画_程序流图怎么画?详细图文解析绘制程序流程图
  4. BSPreloadTableVew带有预加载功能的tableView
  5. NLPIR大数据处理技术实现多种类智能挖掘
  6. 003.XE3包含了TPerlRegEx的单元
  7. 进击的UI---------------------UIStepper(加减)
  8. Git 的 .gitignore 配置
  9. ASP.NET Core跨域设置
  10. python后端开发web_最简易的python web框架的后端实现
  11. 拒绝卡顿——在WPF中使用多线程更新UI
  12. CSS 绘制一个时钟
  13. Pyinstller打包的exe文件反编译
  14. Offline/Batch RL简介
  15. 转载:手机银行技术讨论2
  16. java coverage_Java Coverage(Cobertura)工具
  17. SQLServer数据库设置主键和主键自增
  18. Lambda 构造方法引用 -- 类名::new
  19. Java进阶学习资料,java小程序开发面试题
  20. 字幕翻译,如何合并和拆分过分断句

热门文章

  1. html弹出式登录窗口(DIV悬浮窗口)实现
  2. 基于微信小程序的电影院购票平台——计算机毕业设计
  3. Google地图的Street View和Mapplets
  4. Android点选下拉列表框选项,获取选项内容
  5. 微信小程序开发(四)入门之打卡功能开发
  6. ETABS结构指标查看
  7. python爬取并分析淘宝商品信息
  8. WPF GridSplitter中需要设置HorizontalAlignment和VerticalAlignment
  9. 怎么才能写出好的代码
  10. Android TableLayout记