• 【React-Hooks基础】入门级详解——useState / useEffect /自定义hook


    前言

    博主主页👉🏻蜡笔雏田学代码
    专栏链接👉🏻React专栏
    今天来学习下react中非常重要的一个知识:Hooks
    感兴趣的小伙伴一起来看看吧~🤞

    在这里插入图片描述

    Hooks概念理解

    1. 什么是hooks

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

    React体系里组件分为 类组件函数组件

    经过多年的实战,函数组件是一个更加匹配React的设计理念 UI = f(data),也更有利于逻辑拆分与重用的组件表达形式,而先前的函数组件是不可以有自己的状态的,为了能让函数组件可以拥有自己的状态,所以从react v16.8开始,Hooks应运而生.

    注意点:

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

    2. Hooks解决了什么问题

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

    组件的逻辑复用

    在hooks出现之前,react先后尝试了 mixins混入,HOC高阶组件,render-props等模式
    但是都有各自的问题,比如mixin的数据来源不清晰,高阶组件的嵌套问题等等

    class组件自身的问题

    class组件就像一个厚重的‘战舰’ 一样,大而全,提供了很多东西,有不可忽视的学习成本,比如各种生命周期,this指向问题等等,而我们更多时候需要的是一个轻快灵活的’快艇’

    useState

    1. 基础使用

    作用

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2. 状态的读取和修改

    读取状态

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

    修改状态

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

    注意事项

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

    3. 组件的更新过程

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

    组件第一次渲染

    1. 从头开始执行该组件中的代码逻辑
    2. 调用 useState(0) 将传入的参数作为状态初始值,即:0
    3. 渲染组件,此时,获取到的状态 count 值为: 0

    组件第二次渲染

    1. 点击按钮,调用 setCount(count + 1) 修改状态,因为状态发生改变,所以,该组件会重新渲染
    2. 组件重新渲染时,会再次执行该组件中的代码逻辑
    3. 再次调用 useState(0),此时 React 内部会拿到最新的状态值而非初始值,比如,该案例中最新的状态值为 1
    4. 再次渲染组件,此时,获取到的状态 count 值为:1

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

    4. 使用规则

    useState 函数可以执行多次,每次执行互相独立,每调用一次为函数组件提供一个状态

    function List(){
      // 以字符串为初始值
      const [name, setName] = useState('cp')
      // 以数组为初始值
      const [list,setList] = useState([])
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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的顺序不是固定的,这是不可以的!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 可以通过开发者工具查看hooks状态

    useEffect

    1. 理解函数副作用

    什么是副作用

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

    常见的副作用

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

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

    2. 基础使用

    作用

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

    使用步骤

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

    3. 依赖项控制执行时机

    不添加依赖项

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

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

    添加空数组

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

    useEffect(()=>{
    	 console.log('副作用执行了')
    },[])
    
    • 1
    • 2
    • 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>   
            </>  
        )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意事项

    useEffect 回调函数中用到的数据(比如,count)就是依赖数据,就应该出现在依赖项数组中,如果不添加依赖项就会有bug出现

    某种意义上 hook的出现 就是想不用生命周期概念也可以写业务代码

    清理副作用

    如果想要清理副作用 可以在副作用函数中的末尾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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    阶段小练习 - 自定义hook

    1️⃣需求描述:自定义一个hook函数,实现获取滚动距离Y

    const [y] = useWindowScroll()

    import { useState } from "react"
    
    export function useWindowScroll () {
      const [y, setY] = useState(0)
      window.addEventListener('scroll', () => {
        const h = document.documentElement.scrollTop
        setY(h)
      })
      return [y]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2️⃣需求描述: 自定义hook函数,可以自动同步到本地LocalStorage

    const [message, setMessage] = useLocalStorage(key,defaultValue)

    1. message可以通过自定义传入默认初始值
    2. 每次修改message数据的时候 都会自动往本地同步一份
    import { useEffect, useState } from 'react'
    
    export function useLocalStorage (key, defaultValue) {
      const [message, setMessage] = useState(defaultValue)
      // 每次只要message变化 就会自动同步到本地ls
      useEffect(() => {
        window.localStorage.setItem(key, message)
      }, [message, key])
      return [message, setMessage]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    今天的分享就到这里啦✨ \textcolor{red}{今天的分享就到这里啦✨} 今天的分享就到这里啦

    原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下

    🤞 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

    ⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!

    ✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

  • 相关阅读:
    MarkDown书写语法(常用格式)
    Mac连接虚拟机(Linux系统)
    LNMP动静分离,负载均衡及高可用搭建
    flutter实现左侧导航,拿走即用
    长尾分布系列论文解析(二)Delving into Deep Imbalanced Regression
    SonarQube的使用心得
    栈、队列——双向链表、数组表示以及相互表示
    Codeforces补题
    复习中的一些疑点细节
    exness:欧元区经济意外向好,欧元震荡蓄势等待突破
  • 原文地址:https://blog.csdn.net/xuxuii/article/details/126209441