「React 进阶」 React 全部 Hooks 使用大全 (包含 React v18 版本 )(下)

简介: 一份全方位的 React Hooks 字典。

React Hooks.png

一 前言

React hooks是react16.8 以后,react新增的钩子API,目的是增加代码的可复用性,逻辑性,弥补无状态组件没有生命周期,没有数据管理状态state的缺陷。本章节笔者将介绍目前 React 提供的所有 hooks ,介绍其功能类型和基本使用方法。

创作不易,希望屏幕前的你能给笔者赏个,以此鼓励我继续创作前端硬文。🌹🌹🌹

二 hooks 之状态派生与保存

2.1 useMemo

useMemo 可以在函数组件 render 上下文中同步执行一个函数逻辑,这个函数的返回值可以作为一个新的状态缓存起来。那么这个 hooks 的作用就显而易见了:

场景一:在一些场景下,需要在函数组件中进行大量的逻辑计算,那么我们不期望每一次函数组件渲染都执行这些复杂的计算逻辑,所以就需要在 useMemo 的回调函数中执行这些逻辑,然后把得到的产物(计算结果)缓存起来就可以了。

场景二:React 在整个更新流程中,diff 起到了决定性的作用,比如 Context 中的 provider 通过 diff value 来判断是否更新

useMemo 基础介绍:

const cacheSomething = useMemo(create,deps)
  • ① create:第一个参数为一个函数,函数的返回值作为缓存值,如上 demo 中把 Children 对应的 element 对象,缓存起来。
  • ② deps: 第二个参数为一个数组,存放当前 useMemo 的依赖项,在函数组件下一次执行的时候,会对比 deps 依赖项里面的状态,是否有改变,如果有改变重新执行 create ,得到新的缓存值。
  • ③ cacheSomething:返回值,执行 create 的返回值。如果 deps 中有依赖项改变,返回的重新执行 create 产生的值,否则取上一次缓存值。

useMemo 基础用法:

派生新状态:

function Scope() {
   
   
    const keeper = useKeep()
    const {
   
    cacheDispatch, cacheList, hasAliveStatus } = keeper

    /* 通过 useMemo 得到派生出来的新状态 contextValue  */
    const contextValue = useMemo(() => {
   
   
        return {
   
   
            cacheDispatch: cacheDispatch.bind(keeper),
            hasAliveStatus: hasAliveStatus.bind(keeper),
            cacheDestory: (payload) => cacheDispatch.call(keeper, {
   
    type: ACTION_DESTORY, payload })
        }

    }, [keeper])
    return <KeepaliveContext.Provider value={
   
   contextValue}>
    </KeepaliveContext.Provider>
}

如上通过 useMemo 得到派生出来的新状态 contextValue ,只有 keeper 变化的时候,才改变 Provider 的 value 。

缓存计算结果:

function Scope(){
   
   
    const style = useMemo(()=>{
   
   
      let computedStyle = {
   
   }
      // 经过大量的计算
      return computedStyle
    },[])
    return <div style={
   
   style} ></div>
}

缓存组件,减少子组件 rerender 次数:

function Scope ({
   
    children }){
   
   
   const renderChild = useMemo(()=>{
   
    children()  },[ children ])
   return <div>{
   
    renderChild } </div>
}

2.2 useCallback

useCallback 基础介绍:

useMemo 和 useCallback 接收的参数都是一样,都是在其依赖项发生变化后才执行,都是返回缓存的值,区别在于 useMemo 返回的是函数运行的结果,useCallback 返回的是函数,这个回调函数是经过处理后的也就是说父组件传递一个函数给子组件的时候,由于是无状态组件每一次都会重新生成新的 props 函数,这样就使得每一次传递给子组件的函数都发生了变化,这时候就会触发子组件的更新,这些更新是没有必要的,此时我们就可以通过 usecallback 来处理此函数,然后作为 props 传递给子组件。

useCallback 基础用法:

/* 用react.memo */
const DemoChildren = React.memo((props)=>{
   
   
   /* 只有初始化的时候打印了 子组件更新 */
    console.log('子组件更新')
   useEffect(()=>{
   
   
       props.getInfo('子组件')
   },[])
   return <div>子组件</div>
})

const DemoUseCallback=({
   
    id })=>{
   
   
    const [number, setNumber] = useState(1)
    /* 此时usecallback的第一参数 (sonName)=>{ console.log(sonName) }
     经过处理赋值给 getInfo */
    const getInfo  = useCallback((sonName)=>{
   
   
          console.log(sonName)
    },[id])
    return <div>
        {
   
   /* 点击按钮触发父组件更新 ,但是子组件没有更新 */}
        <button onClick={
   
    ()=>setNumber(number+1) } >增加</button>
        <DemoChildren getInfo={
   
   getInfo} />
    </div>
}

三 hooks 之工具 hooks

3.1 useDebugValue

我们不推荐你向每个自定义 Hook 添加 debug 值。当它作为共享库的一部分时才最有价值。在某些情况下,格式化值的显示可能是一项开销很大的操作。除非需要检查 Hook,否则没有必要这么做。因此,useDebugValue 接受一个格式化函数作为可选的第二个参数。该函数只有在 Hook 被检查时才会被调用。它接受 debug 值作为参数,并且会返回一个格式化的显示值。

useDebugValue 基础介绍:

useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。这个hooks目的就是检查自定义hooks。

useDebugValue 基本使用:

function useFriendStatus(friendID) {
   
   
  const [isOnline, setIsOnline] = useState(null);
  // ...
  // 在开发者工具中的这个 Hook 旁边显示标签
  // e.g. "FriendStatus: Online"
  useDebugValue(isOnline ? 'Online' : 'Offline');

  return isOnline;
}

3.2 useId

useID 基础介绍:

useId 也是 React v18 产生的新的 hooks , 它可以在 client 和 server 生成唯一的 id , 解决了在服务器渲染中,服务端和客户端产生 id 不一致的问题,更重要的是保障了 React v18 中 streaming renderer (流式渲染) 中 id 的稳定性。

低版本 React ssr 存在的问题:

比如在一些项目或者是开源库中用 Math.random() 作为 ID 的时候,可以会有一些随机生成 id 的场景:

const rid = Math.random() + '_id_'  /* 生成一个随机id  */
function Demo (){
   
   
   // 使用 rid 
   return <div id={
   
   rid} ></div>
}

这在纯客户端渲染中没有问题,但是在服务端渲染的时候,传统模式下需要走如下流程:

e54da686-6d8e-4431-a378-c05ac49cb6fb.png

在这个过程中,当服务端渲染到 html 和 hydrate 过程分别在服务端和客户端进行,但是会走两遍 id 的生成流程,这样就会造成 id不一致的情况发生。useId 的出现能有效的解决这个问题。

useId 基本用法:

function Demo (){
   
   
   const rid = useId() // 生成稳定的 id 
   return <div id={
   
   rid} ></div>
}

v18 ssr

在 React v18 中 对 ssr 增加了流式渲染的特性 New Suspense SSR Architecture in React 18 , 那么这个特性是什么呢?我们来看一下:

在传统 React ssr 中,如果正常情况下, hydrate 过程如下所示:

WechatIMG6936.jpeg

刚开始的时候,因为服务端渲染,只会渲染 html 结构,此时还没注入 js 逻辑,所以我们把它用灰色不能交互的模块表示。(如上灰色的模块不能做用户交互,比如点击事件之类的。)

hydrate js 加载之后,此时的模块可以正常交互,所以用绿色的模块展示。

但是如果其中一个模块,服务端请求数据,数据量比较大,耗费时间长,我们不期望在服务端完全形成 html 之后在渲染,那么 React 18 给了一个新的可能性。可以使用 包装页面的一部分,然后让这一部分的内容先挂起。

接下来会通过 script 加载 js 的方式 流式注入 html 代码的片段,来补充整个页面。接下来的流程如下所示:

d94d8ddb-bdcd-4be8-a851-4927c7966b99.png

在这个原理基础之上, React 个特性叫 Selective Hydration,可以根据用户交互改变 hydrate 的顺序

比如有两个模块都是通过 Suspense 挂起的,当两个模块发生交互逻辑时,会根据交互来选择性地改变 hydrate 的顺序。

ede45613-9994-4e77-9f50-5b7c1faf1160.png

如上 C D 选择性的 hydrate 就是 Selective Hydration 的结果。那么回到主角 useId 上,如果在 hydrate 过程中,C D 模块 id 是动态生成的,比如如下:

let id = 0
function makeId(){
   
   
  return id++
}
function Demo(){
   
   
  const id = useRef( makeId() )
  return <div id={
   
   id}  >...</div>
}

那么如果组件是 Selective Hydration , 那么注册组件的顺序服务端和客户端有可能不统一,这样表现就会不一致了。那么用 useId 动态生成 id 就不会有这个问题产生了,所以说 useId 保障了 React v18 中 streaming renderer (流式渲染) 中 id 的稳定性。

四 总结

本文详细介绍了 React Hooks 产生初衷以及 React Hooks,希望看到这篇文章的同学,可以记住每一个 hooks 的使用场景,在项目中熟练使用起来。

参考文档

相关文章
|
30天前
|
前端开发 JavaScript 开发者
深入理解React Hooks:提升前端开发效率的关键
【10月更文挑战第5天】深入理解React Hooks:提升前端开发效率的关键
|
22天前
|
前端开发 JavaScript
React Hooks 全面解析
【10月更文挑战第11天】React Hooks 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性,简化了状态管理和生命周期管理。本文从基础概念入手,详细介绍了 `useState` 和 `useEffect` 的用法,探讨了常见问题和易错点,并提供了代码示例。通过学习本文,你将更好地理解和使用 Hooks,提升开发效率。
54 4
|
24天前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
30天前
|
前端开发 JavaScript API
探索React Hooks:前端开发的革命性工具
【10月更文挑战第5天】探索React Hooks:前端开发的革命性工具
|
10天前
|
前端开发 JavaScript 开发者
“揭秘React Hooks的神秘面纱:如何掌握这些改变游戏规则的超能力以打造无敌前端应用”
【10月更文挑战第25天】React Hooks 自 2018 年推出以来,已成为 React 功能组件的重要组成部分。本文全面解析了 React Hooks 的核心概念,包括 `useState` 和 `useEffect` 的使用方法,并提供了最佳实践,如避免过度使用 Hooks、保持 Hooks 调用顺序一致、使用 `useReducer` 管理复杂状态逻辑、自定义 Hooks 封装复用逻辑等,帮助开发者更高效地使用 Hooks,构建健壮且易于维护的 React 应用。
22 2
|
14天前
|
前端开发 开发者
React 提供的其他重要 Hooks
【10月更文挑战第20天】React 提供了一系列强大的 Hooks,除了 `useRef` 之外,还有许多其他重要的 Hooks,它们共同构成了函数式组件开发的基础。
30 6
|
22天前
|
前端开发 JavaScript 开发者
React Hooks
10月更文挑战第13天
31 1
|
22天前
|
前端开发 开发者 UED
React 18 与之前版本的主要区别
【10月更文挑战第12天】 总的来说,React 18 的这些区别体现了 React 团队对于提升应用性能、用户体验和开发效率的持续努力。开发者需要适应这些变化,充分利用新特性来构建更出色的应用。同时,随着技术的不断发展,React 也将继续演进,为开发者带来更多的创新和便利。
|
28天前
|
前端开发
|
27天前
|
前端开发 JavaScript API
自定义React Hooks综合指南
本文介绍了React Hooks及其在组件开发中的作用,重点讲解了自定义Hook的创建和使用方法。通过实例展示了如何创建`useWindowWidth`、`useFetch`和`useForm`等自定义Hook,并分享了使用自定义Hook的最佳实践。文章强调了自定义Hook在提高代码复用性和组件可维护性方面的重要性。
43 0