• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

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

武飞扬头像
月光晒了很凉快
帮助3


1. 带来了什么

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

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

2. 创建项目

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

  1. npx create-react-app myapp
  2. npm init react-app myapp
  3. yarn create react-app myapp

注意:

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

3. 入口文件的改变

import React from 'react'
// react18它引入ReactDOM类的位置发生改变
import ReactDOM from 'react-dom/client'
// 在react18之后,不要用此方案来引入ReactDOM类
// import ReactDOM from 'react-dom'
import App from './App'

// 把虚拟dom挂载到真实dom中的方法也发生了改变 由原来的render方法,变为 createRoot(dom节点).render(<App/>)
// 支持Concurrent模式[批处理,让setState都为异步] -- 提升性能
const root = 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 都为异步,无论写在什么样的语法环境中。

import React, { Component } from 'react'

class App extends Component {
  state = {
    count: 100
  }

  addCount = () => {
    // 异步的,写成回调函数的方式,可以获得最新的数据状态
    this.setState(
      state => ({ count: state.count   1 }),
      () => console.log(this.state.count)
    )
    // 此方案在react18之前,它里面的操作是同步的,但在react18之后,它都为concurrent模式,都为异步
    // setTimeout(() => {
    //   this.setState(state => ({ count: state.count   1 }))
    //   console.log(this.state.count)
    // }, 1)
  }

  render() {
    return (
      <div>
        <h3>{this.state.count}</h3>
        <button onClick={this.addCount}>累加count</button>
      </div>
    )
  }
}

export default App
学新通

学新通

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

import React, { Component } from 'react'
// flushSync它方法就可以让里面的操作为同步
import { flushSync } from 'react-dom'

class App extends Component {
  state = {
    count: 100
  }

  addCount = () => {
    // react18中,就想让setState它为同步【可以,但不要在生产中去用,不建议】
    // setState它就是同步的
    flushSync(() => {
      this.setState(state => ({ count: state.count   1 }))
    })
    // 因为setState放在flushSync方法里面了,则它现在是一个同步的,所以在此处可以得到最新的数据
    console.log(this.state.count)
  }

  render() {
    return (
      <div>
        <h3>{this.state.count}</h3>
        <button onClick={this.addCount}>累加count</button>
      </div>
    )
  }
}

export default App
学新通

学新通

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

mock 数据:

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

父组件:

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

const fetchUser = async () => {
  let ret = await (await fetch('/users.json')).json()
  return ret
}

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

  useEffect(() => {
    fetchUser().then(ret => setData(ret))
  }, [])

  return (
    <div>
      {/* 条件渲染 */}
      {data.length == 0 ? <div>加载中...</div> : <User data={data} />}
    </div>
  )
}

export default App
学新通

子组件:

import React from 'react'

const User = ({ data }) => {

  return (
    <div>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  )
}

export default User
学新通

学新通

6. 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 App = () => {
  let [data, setData] = useState(wrapperPromise(fetchUser()))

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

export default App
学新通

子组件:

import React from 'react'

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

export default User
学新通

学新通

7. useTransition降级渲染

概述:

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

使用:

import React, { useState, useTransition } from 'react'
// 可以对于更新渲染进行降级,提高更重要的组件的提前渲染

const App = () => {
  let [count, setCount] = useState(100)
  // isPending 如果在更新等待渲染时isPending为true,没有等待更新不渲染时为false
  // startTransition 它是一个函数,在里面写的更新数据会进行降级
  let [isPending, startTransition] = useTransition()

  const addCount = () => {
    // 对于更新count的数据时行了降级,更新也就会降级
    startTransition(() => {
      setCount(v => v   1)
    })
  }

  return (
    <div>
      {/* count更新它没有哪么的着急,可以让别的数据更新渲染先执行 */}
      <h3>{isPending ? '加载中...' : count}</h3>
      <button onClick={addCount}>      </button>
    </div>
  )
}

export default App
学新通

学新通

8. useDeferredValue节流处理

概述:

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

使用:

父组件:

import React, { useState, useDeferredValue } from 'react'
import Search from './pages/Search'

const App = () => {
  let [kw, setKw] = useState('')
  // 让数据更新降级,起到了节流的效果,让渲染平滑一些
  let deferredValue = useDeferredValue(kw)

  return (
    <div>
      <h3>{kw}</h3>
      <input value={kw} onChange={e => setKw(e.target.value.trim())} />
      <Search kw={deferredValue} />
    </div>
  )
}

export default App
学新通

子组件:

import React from 'react'

const Search = ({ kw }) => {
  console.log(kw)
  const data = Array(1000)
    .fill('')
    .map((_, index) => {
      return '搜索 -- '   index   ' -- '   kw
    })

  return (
    <div>
      <ul>
        {data.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  )
}

export default Search
学新通

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfebeba
系列文章
更多 icon
同类精品
更多 icon
继续加载