React进阶之路(三)-- Hooks

news2024/11/28 7:50:45

文章目录

  • Hooks概念理解
    • 什么是Hooks
    • Hooks解决了什么问题
  • useState
    • 基础使用
    • 状态的读取和修改
    • 组件的更新过程
    • 使用规则
    • 回调函数作为参数
  • useEffect
    • 什么是函数副作用
    • 基础使用
    • 依赖项控制执行时机
    • 清理副作用
    • 发送网络请求
  • useRef
  • UseContext

Hooks概念理解

在这里插入图片描述

什么是Hooks

Hooks的本质:一套能够使函数组件更强大,更灵活的“钩子”

在这里插入图片描述
注意点:

  1. 有了hooks之后,为了兼容老版本,class类组件并没有被移除,俩者都可以使用
  2. 有了hooks之后,不能在把函数成为无状态组件了,因为hooks为函数组件提供了状态
  3. hooks只能在函数组件中使用

Hooks解决了什么问题

Hooks的出现解决了俩个问题 1. 组件的状态逻辑复用 2.class组件自身的问题

  1. 组件的逻辑复用:在hooks出现之前,react先后尝试了 mixins混入,HOC高阶组件,render-props等模式,但是都有各自的问题,比如mixin的数据来源不清晰,高阶组件的嵌套问题等等
  2. class组件自身的问题:class组件就像一个厚重的‘战舰’ 一样,大而全,提供了很多东西,有不可忽视的学习成本,比如各种生命周期,this指向问题等等,而我们更多时候需要的是一个轻快灵活的’快艇’

useState

在这里插入图片描述

基础使用

作用

useState为函数组件提供状态(state)

使用步骤:

  1. 导入 useState 函数
  2. 调用 useState 函数,并传入状态的初始值
  3. 从useState函数的返回值中,拿到状态和修改状态的方法
  4. 在JSX中展示状态
  5. 调用修改状态的方法更新状态

代码实现:

import { useState } from 'react'

function App() {
  // 参数:状态初始值比如,传入 0 表示该状态的初始值为 0
  // 返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)
  const [count, setCount] = useState(0)
  return (
    <button onClick={() => { setCount(count + 1) }}>{count}</button>
  )
}
export default App

状态的读取和修改

读取状态

该方式提供的状态,是函数内部的局部变量,可以在函数内的任意位置使用

修改状态

  1. setCount是一个函数,参数表示最新的状态值
  2. 调用该函数后,将使用新值替换旧值
  3. 修改状态后,由于状态发生变化,会引起视图变化

注意事项

  1. 修改状态的时候,一定要使用新的状态替换旧的状态,不能直接修改旧的状态,尤其是引用类型

在这里插入图片描述

组件的更新过程

函数组件使用 useState hook 后的执行过程,以及状态值的变化

  • 组件第一次渲染
    • 从头开始执行该组件中的代码逻辑
    • 调用 useState(0) 将传入的参数作为状态初始值,即:0
    • 渲染组件,此时,获取到的状态 count 值为: 0
  • 组件第二次渲染
    • 点击按钮,调用 setCount(count + 1) 修改状态,因为状态发生改变,所以,该组件会重新渲染
    • 组件重新渲染时,会再次执行该组件中的代码逻辑
    • 再次调用 useState(0),此时 React 内部会拿到最新的状态值而非初始值,比如,该案例中最新的状态值为 1
    • 再次渲染组件,此时,获取到的状态 count 值为:1

重点一句话:useState 的初始值(参数)只会在组件第一次渲染时生效。也就是说,以后的每次渲染,useState 获取到都是最新的状态值,React 组件会记住每次最新的状态值

import { useState } from 'react'

function App() {
  const [count, setCount] = useState(0)
  // 在这里可以进行打印测试
  console.log(count)
  return (
    <button onClick={() => { setCount(count + 1) }}>{count}</button>
  )
}
export default App

使用规则

  • useState 函数可以执行多次,每次执行互相独立,每调用一次为函数组件提供一个状态 (也就是每个状态互不影响)

    function List(){
      // 以字符串为初始值
      const [name, setName] = useState('cp')
      // 以数组为初始值
      const [list,setList] = useState([])
    }
    
  • useState 注意事项

    • 只能出现在函数组件或者其他hook函数中
    • 不能嵌套在if/for/其它函数中,只能在函数组件的最外层去调用(react按照hooks的调用顺序识别每一个hook)
      let num = 1
      function List(){
        num++
        if(num / 2 === 0){
           const [name, setName] = useState('cp') 
        }
        const [list,setList] = useState([])
      }
      // 俩个hook的顺序不是固定的,这是不可以的!!!
      

回调函数作为参数

使用场景

如果初始 state 需要通过计算才能获得,则可以传入一个函数。参数(也就是回调函数)只会在组件的初始渲染中起作用,后续渲染时会被忽略。

语法

const [name, setName] = useState(()=>{   
  // 编写计算逻辑    return '计算之后的初始值'
})

语法规则

  1. 回调函数return出去的值将作为 name 的初始值
  2. 回调函数中的逻辑只会在组件初始化的时候执行一次

语法选择
3. 如果就是初始化一个普通的数据 直接使用 useState(普通数据) 即可
4. 如果要初始化的数据无法直接得到需要通过计算才能获取到,使用useState(()=>{})

例如我们来一个需求:
在这里插入图片描述

import { useState } from 'react'

function Counter(props) {
  const [count, setCount] = useState(() => {
    return props.count
  })
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>{count}</button>
    </div>
  )
}

function App() {
  return (
    <>
      <Counter count={10} />
      <Counter count={20} />
    </>
  )
}

export default App

useEffect

在这里插入图片描述

什么是函数副作用

什么是副作用?

副作用是相对于主作用来说的,一个函数除了主作用,其他的作用就是副作用。对于 React 组件来说,主作用就是根据数据(state/props)渲染 UI,除此之外都是副作用(比如,手动修改 DOM)

常见的副作用

  1. 数据请求 ajax发送
  2. 手动修改dom
  3. localstorage操作

useEffect函数的作用就是为react函数组件提供副作用处理的!

你可以把useEffect看作是React生命周期方法的一种替代,useEffect可以模拟componentDidMount,componentDidUpdate,和componentWillUnmount的行为。你可以在一个组件中使用多个useEffect,以便将不同的副作用分开处理。useEffect是一个Hook,所以你只能在组件的顶层或者你自定义的Hook中调用它,不能在循环或条件语句中调用它。如果你不需要与外部系统同步,你可能不需要使用useEffect。

基础使用

作用

为react函数组件提供副作用处理

使用步骤

  1. 导入 useEffect 函数
  2. 调用 useEffect 函数,并传入回调函数
  3. 在回调函数中编写副作用处理(例如:dom操作)
  4. 修改数据状态
  5. 检测副作用是否生效
import { useEffect, useState } from 'react'

function App() {
  const [count, setCount] = useState(0)
 
  useEffect(()=>{
    // dom操作
    document.title = `当前已点击了${count}`
  })
  return (
    <button onClick={() => { setCount(count + 1) }}>{count}</button>
  )
}

export default App

依赖项控制执行时机

1.不添加依赖项

组件首次渲染执行一次,以及不管是哪个状态更改引起组件更新时都会重新执行

  1. 组件初始渲染
  2. 组件更新 (不管是哪个状态引起的更新)
useEffect(()=>{
    console.log('副作用执行了')
})

2.添加空数组

组件只在首次渲染时执行一次

useEffect(()=>{
	 console.log('副作用执行了')
},[])

3.添加特定依赖项

副作用函数在首次渲染时执行,在依赖项发生变化时重新执行

function App() {  
    const [count, setCount] = useState(0)  
    const [name, setName] = useState('zs') 
    
    useEffect(() => {    
        console.log('副作用执行了')  
    }, [count])  
    
    return (    
        <>      
         <button onClick={() => { setCount(count + 1) }}>{count}</button>      
         <button onClick={() => { setName('cp') }}>{name}</button>    
        </>  
    )
}

注意事项:

  • useEffect 回调函数中用到的数据(比如,count)就是依赖数据,就应该出现在依赖项数组中,如果不添加依赖项就会有bug出现
  • useEffect回调是在dom渲染之后执行
  • useEffect和vue里的watch有点像,但是执行时机是不同的

清理副作用

如果想要清理副作用 可以在副作用函数中的末尾return一个新的函数,在新的函数中编写清理副作用的逻辑。

注意执行时机为:

  1. 组件卸载时自动执行
  2. 组件更新时,下一个useEffect副作用函数执行之前自动执行
import { useEffect, useState } from "react"


const App = () => {
  const [count, setCount] = useState(0)
  useEffect(() => {
    const timerId = setInterval(() => {
      setCount(count + 1)
    }, 1000)
    return () => {
      // 用来清理副作用的事情
      clearInterval(timerId)
    }
  }, [count])
  return (
    <div>
      {count}
    </div>
  )
}

export default App

发送网络请求

使用场景

如何在useEffect中发送网络请求,并且封装同步 async await操作

语法要求

useEffect中不能是一个异步函数的原因是,useEffect的第一个参数应该是一个返回undefined或者一个清理函数的函数,而不是一个返回Promise的函数。异步函数会返回一个Promise,这个Promise不能被当作一个清理函数来调用。这样做会导致useEffect的行为不符合预期,可能会出现内存泄漏或者数据不一致的问题。

在这里插入图片描述

正确写法

如果你想在useEffect中使用异步函数,你有两种方法:

  • 在useEffect内部定义一个异步函数,并立即调用它。
  • 在useEffect外部定义一个异步函数,并在useEffect内部调用它。但是这样做的话,你需要把这个异步函数放到useEffect的依赖数组中,并且用useCallback来包裹它,以防止不必要的调用。
useEffect(() => {
  // 定义一个异步函数
  const fetchData = async () => {
    // 你可以在这里使用await
    const response = await MyAPI.getData(someId);
    // ...
  }
  // 立即调用这个异步函数
  fetchData();
}, [someId]); // 或者[]如果副作用不需要props或state

// 在useEffect外部定义一个异步函数,并用useCallback包裹它
const fetchData = useCallback(async () => {
  // 你可以在这里使用await
  const response = await MyAPI.getData(someId);
  // ...
}, [someId]); // 这里的依赖项要和useEffect的一致

useEffect(() => {
  // 在useEffect内部调用这个异步函数
  fetchData();
}, [fetchData]); // 这里的依赖项要包含这个异步函数

useRef

在这里插入图片描述

使用场景

在函数组件中获取真实的dom元素对象或者是组件对象

使用步骤

  1. 导入 useRef 函数
  2. 执行 useRef 函数并传入null,返回值为一个对象内部有一个current属性存放拿到的dom对象(组件实例)
  3. 通过ref 绑定要获取的元素或者组件

代码实现:

获取dom

import { useEffect, useRef } from 'react'
function App() {  
    const h1Ref = useRef(null)  
    useEffect(() => {    
        console.log(h1Ref)  
    },[])  
    return (    
        <div>      
            <h1 ref={ h1Ref }>this is h1</h1>    
        </div>  
    )
}
export default App

获取组件实例

函数组件由于没有实例,不能使用ref获取,如果想获取组件实例,必须是类组件

class Foo extends React.Component {  
    sayHi = () => {    
        console.log('say hi')  
    }  
    render(){    
        return <div>Foo</div>  
    }
}
    
export default Foo
import { useEffect, useRef } from 'react'
import Foo from './Foo'
function App() {  
    const h1Foo = useRef(null)  
    useEffect(() => {    
        console.log(h1Foo)  
    }, [])  
    return (    
        <div> <Foo ref={ h1Foo } /></div>  
    )
}
export default App

UseContext

在这里插入图片描述

在这里插入图片描述
UseContext的作用是让你在组件中使用Context,Context是一种在组件树中传递数据的方式,它可以让你在不使用props的情况下,让深层嵌套的组件访问一些全局的状态。使用UseContext的步骤如下:

  • 首先,你需要使用createContext创建一个Context对象,并给它一个默认值。
  • 然后,你需要使用Context.Provider组件包裹你的组件树,并给它一个value属性,这个value就是你要传递的数据。
  • 最后,你可以在任何子组件中使用useContext(Context)来获取这个value,这样你就可以在组件中使用这个数据了。

使用UseContext的好处是,你不需要通过props来一层一层地传递数据,这样可以避免一些不必要的渲染和复杂的逻辑。你也可以在Context中存储一些函数,以便在组件中调用它们。使用UseContext的注意事项是,你需要保证你使用的Context对象是同一个,否则你可能会得到undefined的值。你也需要注意useContext的依赖关系,如果你的Context的value发生变化,那么所有使用了这个Context的组件都会重新渲染,除非你使用了memo或者useMemo来优化性能。

代码实现:

import { createContext, useContext } from 'react'
// 1.创建Context对象
const Context = createContext()

function Foo() {  
    return <div>Foo <Bar/></div>
}

function Bar() {  
    // 3.底层组件通过useContext函数获取数据  
    const name = useContext(Context)  
    return <div>Bar {name}</div>
}

function App() {  
    return (    
        // 2.顶层组件通过Provider 提供数据    
        <Context.Provider value={'this is name'}>     
            <div><Foo/></div>    
        </Context.Provider>  
    )
}

export default App

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

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

相关文章

swift和OC混编报错问题

1.‘objc’ instance method in extension of subclass of ‘xxx’ requires iOS 13.0.0 需要把实现从扩展移到主类实现。iOS13一下扩展不支持objc 2.using bridging headers with framework targets is unsupported 报错 这个错误通常指的是在一个框架目标中使用桥接头是不…

HTTP-HTTPS区别详解

一、HTTP协议 1. GET和POST的请求的区别 Post 和 Get 是 HTTP 请求的两种方法&#xff0c;其区别如下&#xff1a; 应用场景&#xff1a; GET 请求是一个幂等的请求&#xff0c;一般 Get 请求用于对服务器资源不会产生影响的场景&#xff0c;比如说请求一个网页的资源。而 Po…

前端构建工具vite与webpack详解

文章目录 前言什么是构建工具先说说企业级项目里都需要具备哪些功能&#xff1f;这是代码改动后需要做的事情样例总结 一、构建工具他到底承担了哪些脏活累活&#xff1f;二、vite相较于webpack的优势三、 vite会不会取代webpack四、 你必须要理解的vite脚手架和vitecreate-vit…

外贸跨境商城源码:快速开发,系统源码,APP+PC+H5

随着全球电子商务的快速发展&#xff0c;外贸跨境商城已成为商业领域的一股不可忽视的力量。外贸跨境商城源码&#xff0c;即可以快速开发出高效、稳定、安全的外贸跨境商城的系统源码&#xff0c;以及APP、PC端和H5端的用户界面设计&#xff0c;是当前市场上的迫切需求。 一、…

多个电商平台搜索接口是否能聚合使用?

作为一名技术爱好者&#xff0c;我们总会遇到各种各样的技术问题&#xff0c;需要寻找合适的技术解决方案。而在互联网时代&#xff0c;我们可以快速通过搜索引擎获取丰富的技术资源和解决方案。然而&#xff0c;在不同的技术分享中&#xff0c;我们常常会遇到质量参差不齐的文…

个人所得税思维导图参考二 —— 筑梦之路

接上篇&#xff1a; 个人所得税思维导图参考 —— 筑梦之路-CSDN博客 这里继续整理下剩下的内容。 11. 个人所得税税率表

2023年下半年信息系统项目管理师下午真题及答案解析(第三批)

试题一(6分) 项目有A、B、C、D、E、F 6个活动&#xff0c;各活动的关系如下表&#xff1a; 2023年下半年信息系统项目管理师下午真题答案及解析 试题一(6分)

harmonyOS开发

在Cocos Creator中&#xff0c;场景是一个独立的文件资源&#xff0c;可以像打开PSD文件一样在编辑器中双击打开&#xff1b; 场景文件是数据驱动工作流的核心&#xff0c;场景中包括图像资源、动画、特效以及驱动游戏逻辑和表现的脚本&#xff1b; Cocos Creator是一个数据驱…

2023年合成数据最大的利用价值

开发成功的 AI 和 ML 模型需要访问大量高质量数据。但是&#xff0c;收集此类数据具有挑战性&#xff0c;因为&#xff1a; AI/ML 模型可以解决的许多业务问题都需要访问敏感的客户数据&#xff0c;例如个人身份信息 &#xff08;PII&#xff09; 或个人健康信息 &#xff08;…

怎么将竖排文字图片转为可编辑的文本?

我们知道&#xff0c;印刷文字的排版大多是横向从左到右排版的&#xff0c;但有些书籍的文字却是从右到左竖向排版的&#xff0c;而一般的OCR软件并不支持这种排版&#xff0c;会将这种排版的文字图片识别成乱码的&#xff0c;那怎么办呢&#xff1f;下面就是很好的解决方案&am…

2023最新版本 FreeRTOS教程 -9-互斥量(基本使用和解决优先级反转)

互斥量是一种特殊的二进制信号量 使用场景1 &#xff08;互斥访问&#xff09; 外设的独立访问 如打印 协议操作 使用场景2 解决优先级反转 外设的独立访问 如打印 协议操作 使用场景2 解决优先级反转 我们以较为复杂的场景2来分析 -1- 创建三个任务 优先级从低到高&…

重新安装电脑系统Win10步骤教程

我们的电脑系统出现了中病毒、崩溃等问题&#xff0c;就会影响到自己的正常使用。这时候选择给电脑重新安装上系统&#xff0c;就能快速解决这些系统问题了。如果有用户不清楚详细的重装Win10系统步骤&#xff0c;就可以参考下面小编带来的重新安装电脑系统Win10的详细步骤介绍…

MySQL -- 视图

MySQL – 视图 文章目录 MySQL -- 视图一、基本使用二、视图规则和限制 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表&#xff0c;基表的数据变化也会影响到视图。 一、基本使用…

负载平衡介绍

负载均衡 建立在现有网络结构之上&#xff0c;它提供了一种廉价有效透明的方法扩展 网络设备 和 服务器 的带宽、增加 吞吐量 、加强网络数据处理能力、提高网络的灵活性和可用性。 1.1. 四层负载均衡 层负载均衡 vs 七层负载均衡 1.1.1. 四层负载均衡&#xff08; 目标地址和…

UML/SysML建模工具更新(2023.10)(1)StarUML、Software Ideas Modeler

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 工具最新版本&#xff1a;Software Ideas Modeler 14.02 更新时间&#xff1a;2023年10月9日 工具简介 轻量级建模工具&#xff0c;支持UML、BPMN、SysML。 平台&#xff1a;Windo…

前端学习基础知识

环境搭建 windows环境 nodejs版本管理工具NVM nvm全英文也叫node.js version management&#xff0c;是一个nodejs的版本管理工具。nvm和n都是node.js版本管理工具&#xff0c;为了解决node.js各种版本存在不兼容现象可以通过它可以安装和切换不同版本的node.js。 安装学习访…

vue-cli创建自定义preset预设项目

vue-cli创建自定义preset预设项目 背景自定义预设创建默认预设创建预设项目preset.jsonprompts.jstemplate预设模板generator.js 本地预设创建项目 背景 一个 Vue CLI preset 是一个包含创建新项目所需预定义选项和插件的 JSON 对象&#xff0c;让用户无需在命令提示中选择它们…

【LeetCode】每日一题 2023_11_9 逃离火灾(bfs 练习)

文章目录 刷题前唠嗑题目&#xff1a;最长平衡子字符串题目描述代码与解题思路偷看大佬题解 结语 刷题前唠嗑 LeetCode? 启动&#xff01;&#xff01;&#xff01; 嗯&#xff1f;什么&#xff1f;今天是 hard&#xff1f;陷入沉思。。。先看看题吧 题目&#xff1a;最长平…

【面经】如何查看服务器内存和磁盘空间占用

查看服务器内存占用 free -g查看服务器磁盘空间占用 df -h

基于React开发的chatgpt网页版(仿chatgpt)

在浏览github的时候发现了一个好玩的项目本项目&#xff0c;是github大神Yidadaa开发的chatgpt网页版&#xff0c;该开源项目是跨平台的&#xff0c;Web / PWA / Linux / Win / MacOS都可以访问。非常有意思&#xff0c;本人就部署了一套&#xff0c;喜欢的同学可以体验一番。 …