react18介绍

news2024/12/23 11:50:16

改进已有属性,如自动批量处理【setState】、改进Suspense、组件返回undefined不再报错等

支持Concurrent模式,带来新的API,如useTransition、useDeferredValue等

如何升级React 18

npm install react@latest react-dom@latest

npm install @types/react@latest @types/react-dom@latest

react18 使用 ReactDOM.createRoot() 创建一个新的根元素进行渲染,使用该 API,会自动启用并发模式。如果你升级到react18,但没有使用ReactDOM.createRoot()代替ReactDOM.render()时,控制台会打印错误日志要提醒你使用React,该警告也意味此项变更没有造成breaking change,而可以并存,当然尽量是不建议
在这里插入图片描述

import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import App from './app';

interface MyModule extends NodeModule {
    hot: {
        accept: () => void;
    };
}
let myM: MyModule = module as MyModule;
if (myM && myM.hot) {
    myM.hot.accept();
}

// ReactDOM.render(<App />, document.querySelector('#root'));
// ReactDOM.createRoot(document.querySelector('#root') as HTMLElement).render(<App />);

const container = document.querySelector('#root');

// 装载
ReactDOM.createRoot(document.querySelector('#root')).render(
    <React.StrictMode>
        <App />
    </React.StrictMode>,
);
// 卸载
ReactDOM.createRoot(document.querySelector('#root')).unmount();

创建根以渲染或卸载的新方法

react18的更新特点

并发模式 Concurrent Mode(并发模式)
  • react18的新特性是使用现代浏览器的特性构建的,彻底放弃对 IE 的支持。
  • 并发模式是实现并发更新的基本前提
  • react18 中,以是否使用并发特性作为是否开启并发更新的依据。
  • 并发特性指开启并发模式后才能使用的特性,比如:useDeferredValue/useTransition

react17 和 react18 的区别就是:从同步不可中断更新变成了异步可中断更新,react17可以通过一些试验性的API开启并发模式,而react18则全面开启并发模式。

并发模式可帮助应用保持响应,并根据用户的设备性能和网速进行适当的调整,该模式通过使渲染可中断来修复阻塞渲染限制。在并发模式中,React 可以同时更新多个状态。

Automatic Batching自动批量更新state,减少渲染次数

  • react18之前,React Event Handler
  • react18之后,React Event Handler、Promise、setTimeout、native event handler等

如何禁用(不推荐)—— 可以使用ReactDom;提供的flushSync方法

import {flushSync} from 'react-dom'

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
}

react18的新的API

1. Transitions 控制渲染的优先级

新的api是useTransitionstartTransition

渲染分为高优先级和低优先级,高优先级就是正常的state更新,低优先级使用transition Api 包裹

总结:

  • 区别渲染优先级
  • 应对同时大量渲染的情况

比如:当用户在输入框查询数据时,需要实时根据用户输入数据进行搜索提示项的展示。与以往不同的是,提示列表的个数是十分庞大的,每次都在10000条以上。

import {useState} from "react";
import styles from "./index.module.css";
const Home:React.FC = () => {
  const [val,setVal] = useState('');
  const [arr,setArr] = useState<number[]>([]);
  //根据用户输入获取查询列表
  const getList = (e:any) => {
    setVal(e.target.value)
    let arr = Array.from(new Array(10000),item=>Date.now())
    setArr(arr);
  }
  return (
    <div className={styles.box}>
      <input value={val} onChange={getList}/>
      {
          arr.map((item,key)=>(
            <div key={key}>{item}</div>
          ))
      }
    </div>
  )
}
export default Home;

现象:我们快速在表单输入了abcd,但是很明显出现了卡顿现象,大约2s后表单和列表数据都被渲染。

新的api:在更新大数据更新或者大列表dom时,为了页面性能和渲染优化,我们可以对大数据或列表的更新过程采用startTransition优雅降级处理。

import {useState,startTransition} from "react";
import styles from "./index.module.css";
const Home:React.FC = () => {
  const [val,setVal] = useState('');
  const [arr,setArr] = useState<number[]>([]);
  //根据用户输入获取查询列表
  const getList = (e:any) => {
    setVal(e.target.value)
    let arr = Array.from(new Array(10000),item=>Date.now());
    startTransition(()=>{
        setArr(arr);
    })
  }
  return (
    <div className={styles.box}>
      <input value={val} onChange={getList}/>
      {
          arr.map((item,key)=>(
            <div key={key}>{item}</div>
          ))
      }
    </div>
  )
}
export default Home;

现象:此处的输入框数据优化了许多,并且大数据列表展示卡顿达到了一定程度优化。

注意:useTransition和startTransition的功能一模一样,只是通过hooks的展现方式出现,并且增加了保存列表是否在渲染等待的状态。

第一个变量保存是否渲染中的状态,ture表示渲染等待中

第二个变量和startTransition的使用方式一模一样

import React,{useState,useTransition} from "react";
const Home:React.FC = () => {
  const [val,setVal] = useState('');
  const [arr,setArr] = useState<number[]>([]);
  const [pending,transition] = useTransition()
  const getList = (e:any) => {
    setVal(e.target.value)
    let arr = Array.from(new Array(10000),item=>Date.now())
    transition(()=>{
      setArr(arr);
    })
  }
  return (
    <div className={styles.box}>
      <input value={val} onChange={getList}/>
      {
        pending?<h2>loading....</h2>:(
          arr.map((item,key)=>(
            <div key={key}>{item}</div>
          ))
        )
      }
    </div>
  )
}
export default Home;

现象:我们根据useTransition返回的pending状态添加判断,如果列表在渲染中就添加提示加载状态,否则正常显示列表。

2. useDeferredValue——让状态滞后派生

useDeferredValue 的实现效果也类似于 transtion,当迫切的任务执行后,再得到新的状态,而这个新的状态就称之为 DeferredValue。

useDeferredValue 接受一个参数 value ,一般为可变的 state , 返回一个延时状态 deferrredValue。

比如:我们每次的输入或者变化,都会触发一次更新

输入框的值变化的时候,我们使用setTimeout来模拟下向后端请求数据,或者大量计算的耗时操作。这个时候只要输入框的内容发生变化就会触发useEffect,我们用count来进行计数。

import React, {useState, useEffect} from 'react';

const List = (props) => {
  const [list, setList] = useState([]);
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(count => count + 1);
    setTimeout(() => {
      setList([
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
      ]);
    }, 500);
  }, [props.text]);
  return [<p>{'我被触发了' + count + '次'}</p>
    , <ul>{list.map(item => <li>Hello:{item.name} value:{item.value}</li>)}</ul>]
};

export default function App() {
  const [text, setText] = useState("喵爸");

  const handleChange = (e) => {
    setText(e.target.value);
  };
  return (
    <div className="App">
      <input value={text} onChange={handleChange}/>
      <List text={text}/>
    </div>
  );
};

改造后:

import React, {useState, useEffect,useDeferredValue} from 'react';
import {useDebounce} from 'ahooks';

const List = (props) => {
  const [list, setList] = useState([]);
  const [count, setCount] = useState(0);
  useEffect(() => {
    setCount(count => count + 1);
    setTimeout(() => {
      setList([
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
        {name: props.text, value: Math.random()},
      ]);
    }, 500);
  }, [props.text]);
  return [<p>{'我被触发了' + count + '次'}</p>
    , <ul>{list.map(item => <li>Hello:{item.name} value:{item.value}</li>)}</ul>]
};

export default function App() {
  const [text, setText] = useState("喵爸");
  const deferredText = useDeferredValue(text,{timeoutMs:2000});  
  const debounceText = useDebounce(text,{wait:2000});useDebounce



  const handleChange = (e) => {
    setText(e.target.value);
  };
  return (
    <div className="App">
      <input value={text} onChange={handleChange}/>
      <List text={deferredText}/>
      //比较
      <List text={debounceText}/>
    </div>
  );
};

useDeferredValue 和上述 useTransition 本质上有什么异同呢?

相同点:useDeferredValue 本质上和内部实现与 useTransition 一样都是标记成了过渡更新任务。

不同点:useTransition 是把 startTransition 内部的更新任务变成了过渡任务transtion,而 useDeferredValue 是把原值通过过渡任务得到新的值,这个值作为延时状态。 一个是处理一段逻辑,另一个是生产一个新的状态。

3.useSyncExternalStore——订阅外部数据源,触发更新

4.useInetionEffect——用于处理css in js缺陷问题

官方对这个函数也不推荐使用,推荐使用useEffect或者useLayoutEffect代替。

5.useId

useId是新增的用于生成唯一ID值的hook钩子,可客户端和服务器端都可以使用,同时避免 dehydrate 过程中数据不匹配的问题。它主要用于与需要唯一 ID 的可访问性 API 集成的组件库。这解决了 React 17 及更低版本中已经存在的问题,但在 React 18 中更为重要,因为新的流式服务器渲染器如何无序交付 HTML。

react18的改进的API

1.setState 都为异步

setState是异步更新的,setState((pre)=>…)此种更新方式将会依赖上一次的状态值,多个state更新会进行批处理更新,减少渲染次数。

import React from 'react';
const Welcome = () => {
    const [myState, setMyState] = React.useState(1);
    const [flag, setFlag] = React.useState(true);

    console.log('render');

    const handleClick = () => {
        setMyState((myState) => myState + 6);
        console.log('myState1', myState);
        setMyState(myState + 1);
        setMyState((myState) => myState + 6);
        console.log('myState2', myState);
        setFlag((flag) => !flag);
        setTimeout(() => {
            setMyState(myState + 1);
            console.log('myState3', myState);
            setMyState((myState) => myState + 10);
            console.log('myState4', myState);
        }, 1000);
    };
    return (
        <div className="content-box" style={{ height: 'calc(100% - 30px)' }}>
            <h1>Hello world!</h1>
            <p>
                <button onClick={handleClick}>
                    myState:{myState},flag:{flag ? 'true' : 'false'}
                </button>
            </p>
        </div>
    );
};
export default Welcome;

2.Suspense——结合异步组件实现条件渲染

import React, { Suspense, useEffect, useState } from 'react'
import User from './pages/User'

// 网络请求
// 返回值为  Promise
const fetchUser = async () => {
  let ret = await (await fetch('/users.json')).json()
  return ret
}

// 创建一个用于解析promise中数据的方法 仿promise的3个状态
const wrapperPromise = promise => {
  // 定义一个promise的状态
  let status = 'pending'
  // 它就是promise解析出来的数据接受的变量
  let result
  const callbackPromise = promise.then(
    ret => {
      // promise执行成功的,返回成功的状态,并把数据赋值给result
      status = 'success'
      result = ret
    },
    err => {
      // 把状态修改为失败,并把错误赋值给result
      status = 'error'
      result = err
    }
  )

  return {
    // 此方法中,才是把数据获取到
    read() {
      if (status === 'pending') {
        // 抛一个异常,这样它就会再来执行,此时就会有上一次的结果
        throw callbackPromise
      } else if (status === 'success') {
        return result
      } else if (status === 'error') {
        return result
      }
    }
  }
}
const User = ({ users }) => {
  // 通过此方法把promise中的数据读取出来
  let data = users.read()
  return (
    <div>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  )
}

const App = () => {
  let [data, setData] = useState(wrapperPromise(fetchUser()))

  return (
    <div>
      <Suspense fallback={<div>加载中 .......................................</div>}>
        <User users={data} />
      </Suspense>
    </div>
  )
}

export default App

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1406612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学会使用ubuntu——ubuntu22.04使用WebCatlog

Ubuntu22.04使用WebCatlog WebCatlog是适用于Gnu / Linux&#xff0c;Windows或Mac OS X系统的桌面程序。 引擎基于铬&#xff0c;它用于在我们的桌面上处理Web服务。简单点就是把网页单独一个窗口出来显示&#xff0c;当一个app用。本文就是利用WebCatlog安装后的notion编写的…

技术驱动宠物健康:宠物在线问诊系统的高效搭建手册

在数字化时代&#xff0c;技术正在催生出许多创新的医疗服务&#xff0c;而宠物在线问诊系统便是其中一项引领潮流的创举。本文将为你提供一份高效搭建宠物在线问诊系统的手册&#xff0c;通过技术代码示例&#xff0c;让你轻松打造一套技术驱动的宠物健康管理系统。 1. 架构…

中仕教育:事业编招考全流程介绍

一、报名阶段 1. 了解查看招聘信息&#xff1a;查看各类事业编岗位的招聘信息&#xff0c;包括岗位职责、招聘条件、报名时间等。 2. 填写报名表&#xff1a;按照要求填写报名表&#xff0c;包括个人信息、教育背景、工作经历等内容。 3. 提交报名材料&#xff1a;将报名表及…

探索文件与交互:使用PyQt5构建一个高级文件选择器

在当今的应用程序开发中&#xff0c;文件管理和交互是一个重要的组成部分。特别是对于桌面应用程序&#xff0c;提供一个直观、功能丰富的文件选择器是提高用户体验的关键。 本篇博客&#xff0c;我将介绍如何使用Python和PyQt5来构建一个高级的文件选择器&#xff0c;它不仅能…

cad二次开发autolisp(二)

目录 一、选择集1.1 选择集的创建1.2 选择集的编辑1.3 操作选择集 二、命令行设置对话框2.1 设置图层2.2 加载线型2.3 设置字体样式2.4 设置标注样式&#xff08;了解即可&#xff09; 三、符号表3.1 简介3.2 符号表查找3.2 符号表删改增 一、选择集 定义&#xff1a;批量选择…

Springboot 项目启动成功,但是访问接口404

搭建了一个子项目运行&#xff0c;启动没有任何问题&#xff0c;但是访问restful接口404&#xff0c;查阅网上是启动类与包路径问题&#xff0c;刚开始按照网上说的是扫描不到&#xff0c;但是检测我创建的路径并没有问题&#xff0c;具体怎么确定是启动时在扫描创建beanDefini…

Java框架篇面试题

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于java面试题系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基…

需求分析的结构化和面向对象方法

需求分析的方法&#xff0c;主要有结构化&#xff08;SA&#xff09;方法、面向对象分析&#xff08;OOA&#xff09;方法。另外有面向问题域的分析(Problem Domain Oriented Analysis&#xff0c;PDOA)方法&#xff0c;还有一些形式化方法例如VDM ( Vienna Design Method)和Z等…

银行数据仓库体系实践(4)--数据抽取和加载

1、ETL和ELT ETL是Extract、Transfrom、Load即抽取、转换、加载三个英文单词首字母的集合&#xff1a; E&#xff1a;抽取&#xff0c;从源系统(Souce)获取数据&#xff1b; T&#xff1a;转换&#xff0c;将源系统获取的数据进行处理加工&#xff0c;比如数据格式转化、数据精…

AP5191 降压恒流 双灯 12V5A 一切一LED车灯汽车大灯驱动方案

AP5191是一款PWM工作模式,高效率、外围简 单、内置功率MOS管&#xff0c;适用于4.5-150V输入的高 精度降压LED恒流驱动芯片。输出功率150W&#xff0c; 电流6A。 AP5191可实现线性调光和PWM调光&#xff0c;线性调 光脚有效电压范围0.55-2.6V. AP5191 工作频率可以通过RT 外部…

Programming Abstractions in C阅读笔记:p248-p253

《Programming Abstractions in C》学习第69天&#xff0c;p248-p253总结&#xff0c;总计6页。 一、技术总结 “A generalized program for two-player games”如标题所示&#xff0c;该小节强调要学会从一个复杂的程序中抽象出通用的内容——这也是本书的主旨——“Program…

C语言进阶——数据结构之链表

前言 hello&#xff0c;大家好呀&#xff0c;我是Humble 在之前的两篇博客&#xff0c;我们学完了数据结构中的顺序表&#xff0c;还对它进行了一个应用&#xff0c;做了一个通讯录的小项目 那今天我们再来学习一个新的数据结构——链表 引入 我们来回忆一下顺序表 对于顺…

工业智能网关储能物联网应用实现能源的高效利用及远程管理

储能电力物联网是指利用物联网技术和储能技术相结合&#xff0c;实现对电力系统中各种储能设备的智能管理和优化控制。随着可再生能源的不断发展和应用&#xff0c;电力系统面临着越来越大的电力调度和储能需求而储能电力物联网的出现可以有效解决这一问题&#xff0c;提高电力…

领势 跨越|美创科技数据安全管理平台2023年度回顾

领势 跨越 数据安全管理平台的2023 以数字化安全平台为基础的数据安全体系是未来安全建设的重要方向。 研究咨询机构IDC指出&#xff1a;未来&#xff0c;数据安全基础设施管理平台将逐步发展成为各组织数据安全建设的基础设施。 Gartner《中国数据安全治理解析》预测&…

顶顶通呼叫中心中间件机器人压力测试配置(mod_cti基于FreeSWITCH)

介绍 顶顶通呼叫中心中间件机器人压力测试(mod_cit基于FreeSWITCH) 一、配置acl.conf 打开ccadmin-》点击配置文件-》点击acl.conf-》我这里是已经配置好了的&#xff0c;这里的192.168.31.145是我自己的内网IP&#xff0c;你们还需要自行修改 二、配置线路 打开ccadmin-&g…

Node.js Stream.pipeline() Method

Why Stream.pipeline 通过流我们可以将一大块数据拆分为一小部分一点一点的流动起来&#xff0c;而无需一次性全部读入&#xff0c;在 Linux 下我们可以通过 | 符号实现&#xff0c;类似的在 Nodejs 的 Stream 模块中同样也为我们提供了 pipe() 方法来实现。 未使用 Stream p…

解决 ssh: connect to host github.com port 22: Connection timed out

问题 今天使用git克隆github上的代码时&#xff0c;一直报错 原以为是公钥过期了&#xff0c;就尝试修改配置公钥&#xff0c;但是尝试了几次都不行&#xff0c;最终在博客上找到了解决方案&#xff0c;在次记录一下&#xff0c;以备不时之需 解决ssh-connect-to-host-github…

springboot整合MongoDB实战

目录 环境准备 引入依赖 配置yml 注入mongoTemplate 集合操作 文档操作 创建实体 添加文档 查询文档 更新文档 删除文档 环境准备 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-da…

Flink(十五)【Flink SQL Connector、savepoint、CateLog、Table API】

前言 今天一天争取搞完最后这一部分&#xff0c;学完赶紧把 Kafka 和 Flume 学完&#xff0c;就要开始做实时数仓了。据说是应届生得把实时数仓搞个 80%~90% 才能差不多找个工作&#xff0c;太牛马了。 1、常用 Connector 读写 之前我们已经用过了一些简单的内置连接器&#x…

机器学习预测全家桶之单变量输入多步预测,天气温度预测为例,MATLAB代码

截止到本期&#xff0c;一共发了8篇关于机器学习预测全家桶的文章。参考文章如下&#xff1a; 1.五花八门的机器学习预测&#xff1f;一篇搞定不行吗&#xff1f; 2.机器学习预测全家桶&#xff0c;多步预测之BiGRU、BiLSTM、GRU、LSTM&#xff0c;LSSVM、TCN、CNN&#xff0c;…