当前位置:

React18和setState、suspense、useTransition、useDeferredValue的使用

访客 2024-04-23 424 0


1.带来了什么

  • 改进已有属性,如自动批量处理【setState】、改进Suspense、组件返回undefined不再报错等
  • 支持Concurrent模式,带来新的API,如useTransition、useDeferredValue等

注意:React升级对于开发者而言,无需重写代码就能够使用React18

2.创建项目

用以下几种方案创建出来的项目使用为react18版本:

  1. npxcreate-react-appmyapp
  2. npminitreact-appmyapp
  3. yarncreatereact-appmyapp

注意:

  1. nodejs版本一定要为16.x及以上版本,如果你用的是win笔记本,则操作系统不能低于win10
  2. react18中的webpack版本为5版本

3.入口文件的改变

importReactfrom'react'//react18它引入ReactDOM类的位置发生改变importReactDOMfrom'react-dom/client'//在react18之后,不要用此方案来引入ReactDOM类//importReactDOMfrom'react-dom'importAppfrom'./App'//把虚拟dom挂载到真实dom中的方法也发生了改变由原来的render方法,变为createRoot(dom节点).render(<App/>)//支持Concurrent模式[批处理,让setState都为异步]--提升性能constroot=ReactDOM.createRoot(document.getElementById('root'));root.render(<React.StrictMode><App/></React.StrictMode>);//也可以使用React17中的方案//不支持Concurrent模式,所以在react18之后就不要写此方案//ReactDOM.render(//<React.StrictMode>//<App/>//</React.StrictMode>,//document.getElementById('root')//)

4.setState

在react18之后,setState都为异步,无论写在什么样的语法环境中。

importReact,{Component}from'react'classAppextendsComponent{state={count:100}addCount=()=>{//异步的,写成回调函数的方式,可以获得最新的数据状态this.setState(state=>({count:state.count1}),()=>console.log(this.state.count))//此方案在react18之前,它里面的操作是同步的,但在react18之后,它都为concurrent模式,都为异步//setTimeout(()=>{//this.setState(state=>({count:state.count1}))//console.log(this.state.count)//},1)}render(){return(<div><h3>{this.state.count}</h3><buttononClick={this.addCount}>累加count</button></div>)}}exportdefaultApp

如果在react18中,我们想要让setState变为同步,我们可以使用flushSync方法:

importReact,{Component}from'react'//flushSync它方法就可以让里面的操作为同步import{flushSync}from'react-dom'classAppextendsComponent{state={count:100}addCount=()=>{//react18中,就想让setState它为同步【可以,但不要在生产中去用,不建议】//setState它就是同步的flushSync(()=>{this.setState(state=>({count:state.count1}))})//因为setState放在flushSync方法里面了,则它现在是一个同步的,所以在此处可以得到最新的数据console.log(this.state.count)}render(){return(<div><h3>{this.state.count}</h3><buttononClick={this.addCount}>累加count</button></div>)}}exportdefaultApp

5.条件渲染传异步数据给子组件

mock数据:

[{"id":1,"name":"张三"},{"id":2,"name":"英子"},{"id":3,"name":"乐乐"}]

父组件:

importReact,{useEffect,useState}from'react'importUserfrom'./pages/User'constfetchUser=async()=>{letret=await(awaitfetch('/users.json')).json()returnret}constApp=()=>{let[data,setData]=useState([])useEffect(()=>{fetchUser().then(ret=>setData(ret))},[])return(<div>{/*条件渲染*/}{data.length==0?<div>加载中...</div>:<Userdata={data}/>}</div>)}exportdefaultApp

子组件:

importReactfrom'react'constUser=({data})=>{return(<div><ul>{data.map(item=>(<likey={item.id}>{item.name}</li>))}</ul></div>)}exportdefaultUser

6.suspense结合异步组件实现条件渲染

父组件:

importReact,{Suspense,useEffect,useState}from'react'importUserfrom'./pages/User'//网络请求//返回值为PromiseconstfetchUser=async()=>{letret=await(awaitfetch('/users.json')).json()returnret}//创建一个用于解析promise中数据的方法仿promise的3个状态constwrapperPromise=promise=>{//定义一个promise的状态letstatus='pending'//它就是promise解析出来的数据接受的变量letresultconstcallbackPromise=promise.then(ret=>{//promise执行成功的,返回成功的状态,并把数据赋值给resultstatus='success'result=ret},err=>{//把状态修改为失败,并把错误赋值给resultstatus='error'result=err})return{//此方法中,才是把数据获取到read(){if(status==='pending'){//抛一个异常,这样它就会再来执行,此时就会有上一次的结果throwcallbackPromise}elseif(status==='success'){returnresult}elseif(status==='error'){returnresult}}}}constApp=()=>{let[data,setData]=useState(wrapperPromise(fetchUser()))return(<div><Suspensefallback={<div>加载中.......................................</div>}><Userusers={data}/></Suspense></div>)}exportdefaultApp

子组件:

importReactfrom'react'//函数组件,它需要返回jsx而不是一个promise对象constUser=({users})=>{//通过此方法把promise中的数据读取出来letdata=users.read()return(<div><ul>{data.map(item=>(<likey={item.id}>{item.name}</li>))}</ul></div>)}exportdefaultUser

7.useTransition降级渲染

概述:

如果你有很多没那么着急的内容要渲染更新就可以使用此hook函数。它可以对于更新渲染进行降级,提高更重要的组件的提前渲染

使用:

importReact,{useState,useTransition}from'react'//可以对于更新渲染进行降级,提高更重要的组件的提前渲染constApp=()=>{let[count,setCount]=useState(100)//isPending如果在更新等待渲染时isPending为true,没有等待更新不渲染时为false//startTransition它是一个函数,在里面写的更新数据会进行降级let[isPending,startTransition]=useTransition()constaddCount=()=>{//对于更新count的数据时行了降级,更新也就会降级startTransition(()=>{setCount(v=>v1)})}return(<div>{/*count更新它没有哪么的着急,可以让别的数据更新渲染先执行*/}<h3>{isPending?'加载中...':count}</h3><buttononClick={addCount}></button></div>)}exportdefaultApp

8.useDeferredValue节流处理

概述:

该方法使得我们可以延迟更新某个不那么重要的部分,有节流防抖效果。可以将原来的更新进行推迟渲染,把重要的更新数据推到前面去更新渲染去。

使用:

父组件:

importReact,{useState,useDeferredValue}from'react'importSearchfrom'./pages/Search'constApp=()=>{let[kw,setKw]=useState('')//让数据更新降级,起到了节流的效果,让渲染平滑一些letdeferredValue=useDeferredValue(kw)return(<div><h3>{kw}</h3><inputvalue={kw}onChange={e=>setKw(e.target.value.trim())}/><Searchkw={deferredValue}/></div>)}exportdefaultApp

子组件:

importReactfrom'react'constSearch=({kw})=>{console.log(kw)constdata=Array(1000).fill('').map((_,index)=>{return'搜索--'index'--'kw})return(<div><ul>{data.map(item=>(<likey={item}>{item}</li>))}</ul></div>)}exportdefaultSearch

发表评论

  • 评论列表
还没有人评论,快来抢沙发吧~