1、什么是hook?
react hook是react 16.8推出的方法,能够让函数式组件像类式组件一样拥有state、ref、生命周期等属性。

2、为什么要出现hook?
函数式组件是全局当中一个普通函数,在非严格模式下this指向window,但是react内部开启了严格模式,此时this指向undefined,无法像类式组件一样使用state、ref,函数式组件定义的变量都是局部的,当组件进行更新时会重新定义,也无法存储,所以在hook出现之前,函数式组件有很大的局限性,通常情况下都会使用类式组件来进行代码的编写。

3、有哪些常用的hook?
(1) useState
使函数式组件也能保存状态的一个hook,这个hook的入参是状态的初始值,返回值是一个数组,数组里第一个参数为状态的值,第二个参数为修改状态的方法。

// 初始化
const [ count, setCount ] = useState(0)
// 更新
setCount(count+1)

(2) useEffect

函数式组件用来模拟生命周期的hook,可以模拟组件挂载完成、更新完成、即将卸载三个阶段,即componentDidMount、componentDidUpdate、componentWillUnmount。

useEffect的一个参数为函数,表示组件挂载、更新时执行的内容,在函数里再返回一个函数,表示组件即将卸载时调用的函数。

第二个参数为可选项,可传入数组,数组里可以为空,表示不依赖任何状态的变化,即只在组件即将挂载时执行,后续任何状态发生了变化,都不调用此hook。数组里也可以定义一或多个状态,表示每次该状态变化时,都会执行此hook。

useEffect(()=>{
  // 这样模拟的是 componentDidMount
}, []) useEffect(()=>{
  // 这样模拟的是componentDidMount 以及当count发生变化时执行componentDidUpdate
}, [count]) useEffect(()=>{
  return ()=>{
    // 这样模拟的是 componentWillUnmount
 }
}, [])

(3) useContext
在没有hook之前,我们通常都会通过 xxxContext.Provider 和 xxxContext.Consumer 的方式来传递和获取context的值,使用hook之后,传递context的方式不变,但子元素获取context的方式变得更加的简洁。

// 以前的定义方式
const CountContext = React.createContext()
<CountContext.Provider value={{ count: 10 }}>
<...自定义的组件>
</CountContext.Provider> // 子元素
<CountContext.Consumer>
{ value => { console.log(value.count) }} //10
</CountContext.Consumer> //使用context的获取方式
const countObj = useContext(CountContext)
console.log(countObj.count) // 10

(4) useRef

useRef和类式组件中createRef用法比较类似,返回一个ref对象,这个对象在函数的整个生命周期都不变,根据这个特性,有两种比较常见的用法。

① 用于dom元素或者组件上,通过current属性可以获取到dom元素或者类式组件的实例对象。需要注意的是,无论是useRef还是createRef或者是回调形式、字符串形式的ref,都是不能直接给函数式组件定义的,因为函数式组件的this指向undefined,没有实例对象,只能通过forwardRef定义到函数式组件中的某个dom元素。

// 这样就将传递给函数式组件的ref绑定在了函数式组件内部的input标签上
import React, { useRef, forwardRef } from 'react' // 使用函数表达式的方式定义了一个函数式组件
const InputCom = forwardRef((props, ref) => {
  return <input ref={ref}/>
}) export default function refDemo(){
const comRef = useRef()
  return(<div>
     <InputCom ref={comRef}/>
  </div>)
}

② 保存一个数据,该数据如果不手动修改,它在整个生命周期中都不变

const [ count, setCount ] = useState(0)
const prevCount = useState(count)
// 当count发生变化时,组件更新,对count的前一次数据进行保存
useEffect(()=>{
  prevCount.current = count
}, [count])

(5) useReducer
useReducer相当于是useState的升级版,作用与useState类似,都是用来保存状态,但它的不同点在于可以定义一个reducer的纯函数,来处理复杂数据。

// 定义一个处理数据的reducer纯函数
function reducer(prevState, action){
  switch(action.type){
    case 'increment':
      return {...prevState, count: prevState.count + 1 }
    case 'decrement':
      return {...prevState, count: prevState.count - 1 }
    default:
    return prevState
  }
} // 初始化状态
const [ count, dispatch ] = useReducer(reducer, { count: 0 })
// 修改状态,此时的修改需要派发一个action,让传入的reducer函数进行处理
dispatch({ type: 'increment' })

(6) useCallback
函数式组件中,每一次更新状态,自定义的函数都要进行重新的声明和定义,如果函数作为props传递给子组件,会造成子组件不必要的重新渲染,有时候子组件并没有使用到父组件发生变化的状态,此时可以使用useCallback来进行性能优化,它会为函数返回一个记忆的值,如果依赖的状态没有发生变化,那么则不会重新创建该函数,也就不会造成子组件不必要的重新渲染。

import React, { useState, useCallback, memo } from 'react'
const AddBtn = memo((props)=>{ // 使用函数表达式的方式定义了一个函数式组件
return<button onClick={props.increment}>+1</button>
}) export default function CallBackPerformance(){
const [ count, setCount ] = useState(0)
const [ show, setShow ] = useState(true)
const increment1 = () => {
console.log('increment1被调用了')
setCount(count+1)
  } const increment2 = useCallback(()=>{ // 使用了useCallback来优化的函数
console.log('increment2被调用了')
setCount(count+1)
},[count]) return(<div>
<div>当前计数:{count}</div>
<AddBtn increment={increment1} name="1"/>
<AddBtn increment={increment2} name="2"/>
<button onClick={e => setShow(!show)}>切换show</button>
</div>)
}
// 当show这个状态发生变化时,子组件increment1会重新渲染,increment2不会重新渲染

(7) useMemo

useMemo也是返回一个记忆的值,如果依赖的内容没有发生改变的话,这个值也不会发生变化,useMemo与useCallback的不同点在于useMemo需要在传入的函数里需要return 一个值,这个值可以是对象、函数,格式如下。

useMemo(()=>{
return { count }
}, [count]) // 使用useCallback时
const increment2 = useCallback(()=>{
  setCount(count+1)
},[count]) // 使用useMemo模拟useCallback
const increment2 = useCallback(()=>{
  return ()=>{
    setCount(count+1)
  }
},[count]) // useMemo的应用场景,当要进行一些复杂的计算时,
//计算的值没有发生变化,并不需要每一次更新都重新计算 import React, { useState, useMemo } from 'react'
const calculateNum = (count) => {
console.log('total重新计算了')
let total = 0
for(let i = 0; i <= count; i++){
total += i
}
return total
} export default function ComplexUseMemo(){
const [ count, setCount ] = useState(10)
const [ show, setShow ] = useState(true)
const total = useMemo(()=>{
return calculateNum(count)
}, [count])
return(<div>
<div>{total}</div>
<button onClick={e=>setCount(count+1)}>+1</button>
<button onClick={e=>setShow(!show)}>切换show</button>
</div>)
}

(8) useImperativeHandle
这个是与forwardRef配合来使用的,当我们对函数式组件使用forwardRef将ref指定了dom元素之后,那就父组件就可以任意的操作指定的dom元素,使用useImperativeHandle就是为了控制这样的一种行为,指定父元素可操作的子元素的方法。

import React, {  useRef, useImperativeHandle, forwardRef } from 'react'
const InputComp = forwardRef((props, ref)=>{
const childInputRef = useRef()
useImperativeHandle(ref, ()=>({
focus: ()=>{
childInputRef.current.focus()
}
}), [childInputRef.current]) return<input ref={childInputRef}></input>
}) export default function ImperativeHookDemo() {
const inputRef = useRef()
return(<div>
<InputComp ref={inputRef}/>
<button onClick={e=>inputRef.current.focus()}>聚焦</button>
</div>)
}

(9) useLayoutEffect

这个方法与useEffect类似,只是执行的顺序稍有不同,useEffect是在组件渲染绘制到屏幕上之后,useLayoutEffect是render和绘制到屏幕之间。

4、如何自定义hook?
hook只能定义在函数式组件中,不能在普通函数中使用,如果我们想要使用到上面的hook来封装一些方法供很多个组件调用,这时候就需要自定义hook,自定义hook的命名就是在函数名前加 use,函数名由 saveInfo 改为 useSaveInfo 即可。

react中常见hook的使用方式与区别的更多相关文章

  1. css中常见几种float方式以及倒计时(刷新页面不清)

    css中常见几种float方式 http://jingyan.baidu.com/article/72ee561a670269e16138dfd5.html <script type=" ...

  2. React中组件间通信的方式

    React中组件间通信的方式 React中组件间通信包括父子组件.兄弟组件.隔代组件.非嵌套组件之间通信. Props props适用于父子组件的通信,props以单向数据流的形式可以很好的完成父子组 ...

  3. ajax中Post和Get请求方式的区别?

    ajax中Post和Get请求方式的区别: 1.Post传输数据时,不需要在URL中显示出来,而Get方法要在URL中显示. 2.Post传输的数据量大,可以达到2M,而Get方法由于受到URL长度的 ...

  4. 整理下react中常见的坑

    其实有些也不能算是坑,有些是react的规定,或者是react的模式和平常的js处理的方式不同罢了 1.setState()是异步的this.setState()会调用render方法,但并不会立即改 ...

  5. react创建组件的几种方式及其区别

    react创建组件有如下几种方式 ①.函数式定义的无状态组件 ②.es5原生方式React.createClass定义的组件   ③.es6形式的extends React.Component定义的组 ...

  6. React创建组件的三种方式及其区别

    内容转载于http://www.cnblogs.com/wonyun/p/5930333.html React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归; 具体的三种方式: ...

  7. Objective-C 中self.与_访问方式的区别

    Objective-C中属性self.a与_a访问的区别: 在OC中我们可以通过指令@property定义属性. OC对属性封装了许多方法,同时也会自动实现一些方法,相比实例变量,感觉更加面向对象些. ...

  8. 浅谈HTTP中GET和POST请求方式的区别

    浅谈HTTP中GET和POST请求的区别 HTTP认知: HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议.HTTP的底层是TCP/IP.所以GET和POST的底层也是TCP/IP,也 ...

  9. React中组件之间通信的方式

    一.是什么 我们将组件间通信可以拆分为两个词: 组件 通信 回顾Vue系列的文章,组件是vue中最强大的功能之一,同样组件化是React的核心思想 相比vue,React的组件更加灵活和多样,按照不同 ...

  10. .NET中常见的加解密方式

    在互联网普及的初期,人们更关注单纯的连接性,以不受任何限制地建立互联网为最终目的.正如事情都具有两面性,互联网的便捷性给人们带来了负面问题,计算机病毒的侵害.信息泄露.网络欺诈等利用互联网的犯罪行为日 ...

随机推荐

  1. #Powerbi函数学习 SELECTEDVALUE与ISFILTERED

    Power BI中的DAX函数ISFILTERED可以用来判断一个表或者一个列是否被筛选器所影响. 这个函数的语法很简单,就是ISFILTERED(<table_or_column_name&g ...

  2. 2021-06-22:现有司机N*2人,调度中心会将所有司机平分给A、B两个区域,第 i 个司机去A可得收入为income[i][0],第 i 个司机去B可得收入为income[i][1],返回所有调

    2021-06-22:现有司机N*2人,调度中心会将所有司机平分给A.B两个区域,第 i 个司机去A可得收入为income[i][0],第 i 个司机去B可得收入为income[i][1],返回所有调 ...

  3. 解决:django.db.utils.OperationalError: no such table: auth_user

    解决:django.db.utils.OperationalError: no such table: auth_user 我们在创建Django项目的时候已经创建这个表了,表一般都保存在轻量级数据库 ...

  4. Java商城网站系统设计与实现(带源码)

    基于Java的商城网站系统设计与实现 功能介绍 平台采用B/S结构,后端采用主流的Springboot框架进行开发,前端采用主流的Vue.js进行开发. 整个平台包括前台和后台两个部分. 前台功能包括 ...

  5. go语言中实现生产者-消费者模式有哪些方法呢

    1. 简介 本文将介绍在 Go 语言中实现生产者消费者模式的多种方法,并重点探讨了通道.条件变量的适用场景和优缺点.我们将深入讨论这些方法的特点,以帮助开发者根据应用程序需求选择最适合的方式.通过灵活 ...

  6. Bracket Sequence

    F. Bracket Sequence time limit per test 0.5 seconds memory limit per test 256 megabytes input standa ...

  7. Ado.Net 数据库访问技术(.Net 6版本)

    1. ADO.NET的前世今生 ADO.NET的名称起源于ADO(ActiveX Data Objects),是一个COM组件库,用于在以往的Microsoft技术中访问数据.之所以使用ADO.NET ...

  8. hosts文件妙用,提升网站访问速度!

    一.背景 在讲解hosts文件之前,我们先了解下IP地址与域名的关系. 1.IP地址与域名的关系 IP(Internet Protocol)是一种规定互联网中数据传输的协议,每台连接到互联网中的计算机 ...

  9. uniapp主题切换功能的第一种实现方式(scss变量+vuex)

    随着用户端体验的不断提升,很多应用在上线的时候都要求做不同的主题,最基本的就是白天与夜间主题. 就像b站app主题切换,像这样的 uniapp因为能轻松实现多端发布而得到很多开发者的青睐,但每个端的实 ...

  10. Vue3 之 响应式 API reactive、 effect源码,详细注释

    Vue3之响应式 API reactive. effect源码,详细注释 目录 一.实现响应式 API:reactive.shallowReactive.readonly.shallowReadonl ...