React函数组件Hook

问题: 相对于类组件, 函数组件的编码更简单, 效率也更高, 但函数组件不能有state (旧版)

解决: React 16.8版本设计了一套新的语法来让函数组件也可以有state

  • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

  • Hook也叫钩子,本质就是函数,能让你使用 React 组件的状态和生命周期函数...

  • Hook 语法 基本已经代替了类组件的语法

  • 后面的 React 项目就完全是用Hook语法了

Hook API 索引 – React 官方文档: Hook API 索引 – React

hook函数和普通函数的区别:

hook函数本身就是一个函数。react通过函数名来判断是普通函数还是hook函 数,以useXxx 格式命名的就是hook函数。

Hook函数使用原则:

1.不能在类组件中使用,不能在普通函数中使用

2.只能在函数组件中使用,或其他hook函数中使用【react提供的,第三方的,自定义的】

3..hook函数必须是数量确定的,不能写在逻辑判断中或后,不能写在循环中

4.应用时,一般写在顶级作用域的首行 使用场景

-----1.可以在函数组件中使用

let [msg, setMsg] = useState('')
 function clickHandler(){
 // let [count,setCount] = useState() // 普通函数会报错

 }

-----2.自定hook中可以使用其他hook

function useClickHandler(){
 let [count,setCount] = useState(0)
 }

-----3.如果函数名首字母大写,他会 认为是函数组件,也不会报错

 function ClickHandler(){
 let [count,setCount] = useState(0)
 }

1.useState()

作用:给函数组件添加状态

返回值:是一个数组,第一个元素是状态,第二个元素是设置状态的函数

语法:let [状态, 设置状态函数] = useState(初始值)

import React,{useState} from 'react'

export default function App() {
    console.log('App render')
   let [count,setCount] = useState(0)
    return (
        <div>
            <h3>App</h3>
            <p>{count}</p>
            <p><button onClick={()=>{
             setCount(1000)
            }}>count + 1</button></p>
        </div>
    )
}

2.useEffect

作用:用来模拟函数组件的生命周期 componentDidMount、componentDidUpdate、ComponentWillUnmounted

2.1.用法:

useEffect(回调函数) : 没有第二个参数 模拟 componentDidMount + componentDidUpdate

useEffect(() => {
 console.log('useEffect') 
})
2.2.用法

useEffect(回调函数,[]) 只模拟 componentDidMount

 useEffect(()=>{
        console.log('useEffect')   // componentDidMount
 },[])
2.3.用法

useEffect(回调函数,[某 个自身状态(state) , 某个 外部状态(props), .......])

useEffect(() => { 
 console.log('useEffect')
 }, [count])
2.4.用法

useEffect( return ()=>{ } )   模拟componentWillUnmount

useEffect(()=>{
 console.log('Test useEffect')
 return ()=>{ // componentWillUnmount
 console.log('destroy')
 }
 },[msg,money])

3.useRef

作用 :可以用它获取dom元素

1. 创建一个ref let divRef = useRef()

2. 绑定ref

3. 获取dom元素

import React, { useRef } from "react";
export default function App() {
  let divRef = useRef();
  return (
    <div>
      <div ref={divRef}>
         <h3>app</h3>
         <button onClick={()=>{
            console.log(divRef.current);
         }}>获取DOM元素</button>
      </div>
    </div>
  );
}

4.useContext

作用 :获取从祖先组件传递给后代组件的数据

4.1.创建context对象

context.js 代码

import React from 'react'
// 1. 创建context对象,并暴露出去
const context = React.createContext() 
export default context
4.2.使用Provider组件包裹 组件, 并通过 value 绑定要传的数据

App.jsx 代码

import React from "react";
import Father from "./components/Father50";
import context from "./context";
export default function App() {
  return (
     // 2. 使用Provider包裹组件,并通过value绑定要传输的数据
    <context.Provider value={{ name: "App的内容" }}>
      <div>
        <h3>App</h3>
        <hr />
        <Father />
      </div>
    </context.Provider>
  );
}
4.3. 引入context对象
4.4.通过useContext处理context对象,获取祖先组件传递的数据
import React from 'react'

// 3. 引入context对象
import context from '../context'
import { useContext } from "react";

export default function Father() {
    // 4. 通过useContext处理context对象,获取祖先组件传递的数据
    let {name} = useContext(context)
    return (
        <div>
            <h4>Father</h4>
            <p>Father-context: {name}</p>
            <hr />
        </div>
    )
}

5.useReducer

集中状态管理。相当于是简化版的 redux

import React, { useState } from 'react'
import { useReducer } from 'react'
const initalState = { count: 0, msg: 'atguigu' }
function reducer(state, action) {
    switch (action.type) {
        case 'inc':
            return {
                ...state,
                count: state.count + 1
            }
        case 'dec':
            return {
                ...state,
                count: state.count - 1
            }
        case 'add':
            return {
                ...state,
                msg:state.msg + '+'
            }
        default:
            throw new Error('没有处理case')
    }
}
export default function App() {
    let [state, dispatch] = useReducer(reducer, initalState)
    return (
        <div>
            <p>count: {state.count}</p>
            <p>msg: {state.msg}</p>
            <p><button onClick={()=>{
                dispatch({type:'inc'})
            }}>count + 1</button></p>

            <p><button onClick={()=>{
                dispatch({type:'add'})
            }}>msg + '+'</button></p>
        </div>
    )
}

6.useCallBack

可以缓存一个函数。避免函数的多次创建。性能优化

用法一:

没有第二个参数,函数仍然会被重复创建

  let clickHandler = useCallback(() => {
    setCount(count + 1);
  });

用法二:

第二个参数是空数组,那么函数会被缓存

    let clickHandler = useCallback(()=>{
        // setCount(count + 1)
        // 函数被缓存,可以使用setXxx 第二种用法,获取最新的状态值
        setCount(count=>count + 1)
    },[])

用法三:

第二个参数是数组,并监听 x 个 状态,当这些状态中的一个或多个发生变化时,重新创建函数

  let clickHandler = useCallback(() => {
    setCount(count + 1);
    // 函数被缓存,可以使用setXxx 第二种用法,获取最新的状态值
    // setCount(count=>count + 1)
  }, [count]);

7.React.memo

作用:类似于类组件中的纯组件。当自身状态和外部数据没有变化的时候,不会重新渲染

App.jsx 代码

import React, { Component } from 'react'
import Test from './components/Test56'
export default class App extends Component {
    state = {
        msg:'React'
    }
    render() {
        console.log('App render')
        return (
            <div>
                <h3>App</h3>
                <p>msg: {this.state.msg}</p>
                <p><button onClick={()=>this.setState({
                    msg:'React'
                })}>msg change</button></p>
                <hr />
                <Test msg={this.state.msg}/>
            </div>
        )
    }
}

 Test.jsx 代码

import React from 'react'
import { useState } from 'react'

function Test({msg}) {
    console.log('Test render')
    // useState已经对自身状态做过优化
    let [count,setCount] = useState(0)
    return (
        <div>
            <p>count:{count}</p>
            <p>App-msg: {msg}</p>
            <button onClick={()=>{
                setCount(100)
            }}>count + 1</button>
        </div>
    )
}

export default React.memo(Test)

如图所示:

8.useMemo

作用:缓存一个函数计算的结果,常用来跟useCallback进行比较;useCallback是缓存一个 函数,useMemo缓存函数执行的结果

通俗来讲就是:它是一个优化性能的 Hook,它会记住函数的返回值,只要依赖项(dependency array)没有变化,就会复用之前的计算结果,避免在每次渲染时都重新执行这个可能开销较大的计算

官方详解:

App.jsx 代码

import React from 'react'
import Test from './components/Test57'

export default function App() {
    return (
        <div>
            <Test/>
        </div>
    )
}

Tset.jsx 代码

import React, { useState,useMemo } from 'react';

export default function Test() {
const [count,setCount] = useState(0)
const [val,setVal] = useState(0)

const expensive = useMemo(()=>{
    console.log('================');
    let sum =0
    for(let i=1;i<count;i++){
        sum += i
    }
    return sum
},[count])

// const expensive = (()=>{
//     console.log('================');
// },[count])

    return <div>
        <h4>{count}-{val}-{expensive}</h4>
        <div>
            <button onClick={()=>setCount(count + 1)}>+c1</button>
            <input val={val} onChange={event =>{
                setVal(event.target.value)
            }}/>
        </div>
    </div>;
}

9.useImperativeHandle

它与 forwardRef 结合使用以暴露自定义组件的 refs 给父组件。可以在使用 `ref` 时自定义暴露给父组件的实例值

官方文档:useImperativeHandle – React

APP.jsx 代码

import React from 'react'
import { useRef } from 'react'
import FunTest from './components/FunTest58'

export default function App() {
    // ref可以给绑定类组件,并且可以获取类组件实例对象
    let refClass = useRef()
    // ref本身不能够给函数组件使用,但是可以通过 React.forwardRef()进行扩展
    let refFn = useRef('true')
    /**
     * 当希望在父组件获取子组件的dom对象的时候,可以使用 函数组件配合 React.forwardRef()实现
     */
    return (
        <div>

            <FunTest ref={refFn} />

            <p><button onClick={() => {
                console.log(refClass)
                console.log(refFn)
            }}>获取ref</button></p>

            <p><button onClick={() => {
                refFn.current.changeBg()
            }}>changeBg</button></p>

            <p><button onClick={() => {
                refFn.current.changeFontSize()
            }}>changeBg</button></p>
        </div>
    )
}

FunTest.jsx 代码

import React from "react";
import { useRef, useImperativeHandle } from "react";

function FunTest(props, AppRef) {
  let selRef = useRef()
  
  useImperativeHandle(AppRef,()=>({
    changeBg:()=>{
        selRef.current.style.backgroundColor = "red"
    }
  }))

  return (
    <div>
      <h3 ref={selRef}>FunTest</h3>
    </div>
  );
}
export default React.forwardRef(FunTest);

 如图所示:

10.useLayoutEffect

useLayoutEffect是useEffect的一个版本,在浏览器重新绘制屏幕之前触发。

useEffect在render结束后,你的callback函数执行,但是不会阻塞浏览器渲染

作用:用在处理DOM的时候,当你的useEffect里面的操作需要处理DOM,并且会改变页面的样式,就需要用这个,否 则可能会出现出现闪屏问题, useLayoutEffect里面的callback函数会在DOM更新完成后立即执行,但是会在 浏览器进行任何绘制之前运行完成,阻塞了浏览器的绘制

官方文档:useLayoutEffect – React

App.jsx 代码

import React from 'react'
import Animate from './components/Animate59'

export default function App() {
  return (
    <div>
        <Animate/>
    </div>
  )
}

Animate.jsx 代码

import React, { useEffect, useLayoutEffect, useRef } from 'react'
import TweenMax from 'gsap' // npm i gsap@3.7.0
import '../index.css'

const Animate = () => {
    const REl = useRef(null)

    useLayoutEffect(()=>{
        TweenMax.to(REl.current,0,{x:600})
    },[])
    return (
        <div className="animate">
            <div ref={REl} className="square">
                square
            </div>
        </div>
    )
}
export default Animate

11.useDebugValue

作用:用于在 React 开发者工具中显示 自定义 hook 的标签,只能在自定义hook中使用

官方文档:useDebugValue – React

12.useId

用于生成一个唯一的标识

import React from 'react'
import { useId } from 'react'

export default function App() {
  let id1 = useId()
  let id2 = useId()
  console.log(id1);
  console.log(id2);
  return (
    <div>
          <div>App</div>
    </div>
  )
}

 

13.useTransition

作用:可以将任务设置为非紧急任务

官方文档:useTransition – React

const [isPending, startTransition] = useTransition()
startTransition(()=>{
               
 })

14.useDeferredValue

作用:根据一个状态,设置一个延时的状态。也可以实现,任务渲染的优先级区别

import { useState, useDeferredValue } from 'react';

function SearchPage() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  // ...
}

15.自定义hook函数

作用: 函数组件代码逻辑复用的手段,函数名 useXxx 格式 ,函数中可以使用其他hook函数

App.jsx 代码

import React, {useState} from 'react'
import { useEffect } from 'react'
import usePosition from '../hook/usePosition'
export default function Cat() {
 let {x,y} = usePosition()
 return (
 <div style={{width:100,height:100,border:'1px solid red',position:'absolute',left:x,top:y}}>Cat</div>
 )
}

 usePosition.js 代码

import {useState, useEffect} from 'react'
export default function usePosition() {
 let [x, setX] = useState(0)
 let [y, setY] = useState(0)
 function moveHandler(e) {
 setX(e.clientX)
 setY(e.clientY)
 }
 useEffect(() => {
 window.addEventListener('mousemove', moveHandler)
 return () => {
 window.removeEventListener('mousemove', moveHandler)
 }
 }, [])
 return {x,y}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python的基本介绍以及安装教程

前言&#xff1a; 今天&#xff0c;我将给大家讲解关于python的基本知识&#xff0c;让大家对其有个基本的认识并且附上相应的安装教程以供大家参考。接下来&#xff0c;我们正式进入今天的文章&#xff01;&#xff01;&#xff01; 目录 前言 &#xff08;一&#xff09;P…

6、运行时数据区

Java虚拟机在运行Java程序过程中管理的内存区域&#xff0c;称之为运行时数据区。《Java虚拟机规范》中规定了每一部分的作用。 3.1 程序计数器 程序计数器&#xff08;Program Counter Register&#xff09;也叫PC寄存器&#xff0c;每个线程会通过程序计数器记录当前要执行的…

泰山派开发环境安装及SDK编译

泰山派开发环境安装及SDK编译 1、安装虚拟机、VMware2、下载必要库3、开启ssh4、查看网络5、安装samba 共享文件6、安装git 和 repo7、安装 python2 / python38、安装whiptail9、上传文件至 ubantu10、安装编译环境11、选择板级配置12、编译内核13、全编译14、固件打包15、生成…

轨迹预测后处理之非极大值抑制(NMS)

非极大值抑制是图像处理里面的一种算法&#xff08;比如边缘检测会使用到&#xff09; 轨迹预测这里借鉴了其思想&#xff0c;比如说对于某个场景中的某辆车&#xff0c;我们使用模型预测 64 条轨迹或者更多&#xff0c;以很好地捕获多模态性&#xff0c;同时每条轨迹对应一个…

React Developer Tools安装

问题描述 在react开发中&#xff0c;需要插件来帮助我们开发&#xff0c;例如&#xff1a; 方法 &#xff08;可能需要魔法 进去后搜索&#xff1a; 点击下载即可

QT 界面2.1

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {this->setWindowIcon(QIcon(":/Logo/1bc87d9b4c1ea878d5e0845257a06f7f (1).jpg")); // 图标this->setWindowTitle(&…

计算机网络常见题(持续更新中~)

1 描述一下HTTP和HTTPS的区别 2 Cookie和Session有什么区别 3 如果没有Cookie,Session还能进行身份验证吗&#xff1f; 4 BOI,NIO,AIO分别是什么 5 Netty的线程模型是怎么样的 6 Netty是什么&#xff1f;和Tomcat有什么区别&#xff0c;特点是什么&#xff1f; 7 TCP的三次…

ElasticSearch文档批量操作[ES系列] - 第503篇

历史文章&#xff08;文章累计500&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 《…

Java 算法和数据结构 答案整理,最新面试题

Java中如何使用动态规划求解背包问题&#xff1f; 1、定义子问题&#xff1a; 首先确定动态规划状态&#xff0c;通常以物品数量和背包容量为变量定义子问题&#xff0c;例如dp[i][j]表示前i件物品放入容量为j的背包所能获得的最大价值。 2、确定状态转移方程&#xff1a; 基…

PTA L2-031 深入虎穴 dfs与bfs版

著名的王牌间谍 007 需要执行一次任务&#xff0c;获取敌方的机密情报。已知情报藏在一个地下迷宫里&#xff0c;迷宫只有一个入口&#xff0c;里面有很多条通路&#xff0c;每条路通向一扇门。每一扇门背后或者是一个房间&#xff0c;或者又有很多条路&#xff0c;同样是每条路…

线程和进程有什么区别?

1、典型回答 进程&#xff08;Process&#xff09;和线程&#xff08;Thread&#xff09;是操作系统中两个重要的概念&#xff0c;都是用来执行任务的&#xff0c;它们的定义如下&#xff1a; 进程是指计算机中正在运行的程序的实例。每个进程都有自己的地址空间、内存、文件…

软件测试|Python random模块,超乎想象的强大

Python的random模块是一个非常强大的工具&#xff0c;用于生成随机数和随机选择。它提供了许多函数和方法&#xff0c;可以满足各种随机化需求。本文将介绍random模块的基本功能和常见用法&#xff0c;以帮助读者更好地理解和利用这个模块。 返回整数 random.randange() 语法…

软件测试|time模块的用法,你都掌握了吗?

前言 在Python编程中&#xff0c;时间是一个关键的概念&#xff0c;涉及到计时、延时、日期时间操作等。Python的time模块提供了处理时间相关操作的函数和方法。本文将详细介绍time模块的各种功能和用法&#xff0c;帮助您更好地理解和应用时间操作。 时间戳&#xff08;Time…

瑞吉外卖实战学习--项目搭建

瑞吉外卖实战学习 前言1、创建springBoot 项目&#xff0c;并引用相关依赖2、配置数据库3、通过注解检测项目是否可以启动成功4、配置前端页面的静态映射4.1 前端文件放置的位置4.2 由于存放的位置并不是默认的文件中&#xff0c;需要将这些文件静态映射4.3 检测静态文件是否可…

这回轮到鸿蒙禁用安卓了!!!

1月18日&#xff0c;鸿蒙生态千帆仪式上&#xff0c;华为正式宣布了HarmonyOS NEXT&#xff08;下简称鸿蒙星河版或纯血鸿蒙&#xff09;开发者预览已向开发者开放申请&#xff0c;纯血鸿蒙开始走向普及阶段。伴随着不再兼容安卓的纯血鸿蒙铺开&#xff0c;鸿蒙走进了运营属于自…

【OpenModelica】2 交互式使用OpenModelica-上篇

2 交互式使用OpenModelica 文章目录 2 交互式使用OpenModelica前言一、开始使用交互式对话二、使用交互式的模式三、尝试使用冒泡排序算法四、使用cd()指令 前言 以下是在OpenModelica环境中使用交互式会话处理程序的交互式会话。称为OMShell-OpenModelica Shell。这些示例中的…

return code 1 from org.apache.hadoop.hive.ql.ddl.DDLTask

Bug信息 Error: Error while compiling statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.ddl.DDLTask (state=08S01,code=1)Bug产生的代码 修复hive表分区: msck repair table xxxBug原因排查 分区数量过大 这个是网上查看的说如果一次…

探索生成式AI Agent,让公众自动化触手可及

在科技浪潮的推动下&#xff0c;AI Agent市场正经历深刻变革。Kognitos智能RPA厂商凭借675万美元融资和生成式AI自动化的定位&#xff0c;吸引业界关注。然而&#xff0c;微软早已将ChatGPT融入Power Platform&#xff0c;提供低代码应用开发体验&#xff0c;引领市场。初创公司…

浅谈linux下的进程地址空间(虚拟地址/线性地址)

目录 什么是地址空间 - 虚拟地址空间 地址空间是如何设计的 为什么要有地址空间 什么是地址空间&#xff1f; 示例&#xff1a; 运行之后发现&#xff1a;同一个变量&#xff0c;同一个地址&#xff0c;在运行一段时间后&#xff0c;竟然会在同一时间出现两个不同的值&…

代码随想录day30(2)回溯:组合(leetcode77)

题目要求&#xff1a;给定两个整数 n 和 k&#xff0c;返回 1 ... n 中所有可能的 k 个数的组合。 思路&#xff1a;首先定义两个变量&#xff0c;一个存放符合条件的单一结果&#xff0c;另一个存放符合条件结果的集合&#xff0c;for循环用来横向遍历&#xff0c;递归用来纵…