React18新特性学习(1)

277 阅读5分钟

React18

学习目标 :

  1. 掌握React18 并发模式
  2. 掌握React18 新增特性
  3. 具备React18 实战经验

一、React18

1.新的项目创建

 npx create-react-app my-app
 cd my-app
 npm start

当然也可以直接全局安装react脚手架,装一次 以后都直接create就行。

 npm install -g create-react-app
 create-react-app my-app
 cd my-app
 npm start

2.老项目升级

 //先把依赖中的版本号改为最新,然后删掉 node_modules 文件夹
 //"react": "^18.2.0",
 //"react-dom": "^18.2.0"
 ​
 //然后再在控制台
 npm i

如果在使用Node.js17的应用程序中遇到ERR_OSSL_EVP_UNSUPPORTED错误,很可能是您的应用程序或您正在使用的模块尝试使用OpenSSL3.0 默认不再允许的算法或密钥大小。

 //在控制台输入  设置环境变量,使之不检查
 $env:NODE_OPTIONS="--openssl-legacy-provider"

二、Render API

React18 引入了一个新的root API,支持new concurrent renderer(并发模式的渲染)

老的写法

 import ReactDOM from 'react-dom';
 ReactDOM.render(<App/>,document.getElementById("root"))

新的写法

 import ReactDOM from 'react-dom/client';
 const root = ReactDOM.createRoot(document.getElementById('root'));
 root.render(
   <React.StrictMode>
     <App />
   </React.StrictMode>
 );

React18放弃了对于IE11的支持。

三、自动批量更新State

React18默认开启批处理来实现性能提升。

这里有个要提一下,在index.js中,创建项目时render中默认会有一个严格模式组件<React.StrictMode>,在我们开发模式下会重复地调用生命周期,所以在开发的时候我们要把它删掉否则会影响我们的观察结果。在生产环境下就不会重复调用。

批量处理这个特点呢跟React17有区别的:在React事件处理函数中,React17和React18都能实现批量处理。批量处理是什么意思呢,下面举个栗子:

 import { useState } from 'react'
 ​
 function App() {
   //打印123
   console.log(123)
   //我们这里有 两个useState
   const [name,setName] = useState('芜湖')
   const [age,setAge] = useState(100)
 ​
   
   return (
     <div className="App">
       {name}-{age}
       <button onClick={()=>{//这就是React事件处理函数,在这里执行两次setState()
           setName('起飞')
           setAge(66)
       }}>click</button>
     </div>
   );
 }
 ​
 export default App;

我们会发现:每次点击按钮都只会打印一个123。

那是因为,在React事件处理函数中,同时执行两个setState(),它其实就会进行批量处理,只会做一次虚拟DOM的创建和diff算法的对比,把两次setState()合并了,这样只会一次渲染页面,性能得到提升

但是呢,在React17中,只有React事件处理函数中的状态会被批量处理,像是Promise、setTimeout、原生事件处理中,都无法实现批量处理。而在React18中,都支持了批量处理~~在React18中,React团队也给出了一个flushSync函数,如果在特定情境下,你不希望批量处理,就可以使用这个方法:

 <button onClick={()=>{
     flushSync(()=>{
         setName('起飞')
     })
     flushSync(()=>{
         setAge(66)
     })
 }}>click</button>

用 flushSync 把它们隔开了,这样就会分开成两次更新了。

四、Concurrent Mode(并发模式)

CM本身不是一个功能,而是一个底层设计,它使React能够同时准备多个版本的UI。

在React15的时候,为了对比新老虚拟DOM采用了diff算法,但它底层架构中用的是堆栈diff算法不可中断式的递归更新方式。

假设有三个state,那它只能一个一个按顺序先更新state1然后state2最后state3,并且每一个更新过程都不可中断。更新state的过程有这么几块:

  1. 触发更新
  2. 创建虚拟DOM
  3. 对比虚拟DOM,创建真实DOM渲染

在React16的时候出现了一些新的东西,最主要的是出现了hooks。并且出现了不同于堆栈式的更新机制:React fiber,是可中断的更新机制。

这里有一个网站可以明显地对比这两种更新机制:claudiopro.github.io/react-fiber…。可以很明显地看出堆栈式的更新机制让人非常地难受哈哈哈哈。

那么React fiber是基于 浏览器单线程的一个原生调度算法(requestIduleCallback:它在浏览器宏任务、微任务、RAF、渲染之后执行,时间非常短) 写的一套完整的调度算法。它把我们的创建虚拟DOM、真实DOM、渲染分成无数个小的碎片任务,然后根据优先级(如果有优先级的话)执行任务。如果有高优先级的任务就能够打断低优先级的任务

React fiber分为两个阶段:

  1. 协调阶段(可被打断):找出需要创建的虚拟DOM、需要更新的DOM等等动作。
  2. 提交阶段(不可打断):把DOM更新完。

可以理解为在更新state的过程中的前两个步骤都是可以被打断的,而第三个步骤不行。

React17是一个无新特性的更新版本,作为React18的垫脚石,支持试运行的并发模式。有了React fiber这个底层架构,才能有并发,其实也并不是所有的state的改变同时进行,而是有优先级高的会中断之前在执行的更新,等它更新好后再接着低优先级的state的更新。因为JS只能是单线程。如果在一帧中没有全部更新完,等到下一帧来了会接着进行更新。

终于来到React18,并发模式Concurrent Mode (CM) 不是一个方法,而是一个底层设计。基于这种并发模式,React给出了两个新的API,让开发者可以自己决定优先级的高低。但想要开启并发模式和能够使用第三点的批量更新,前提是渲染方式必须是用新的ReactDOM.createRoot之后再render这种方式。这些呢都需要好好消化一下,明天就来学习这两个API。