一.为什么要有hooks?
1.想要复用一个class类组件太麻烦
react的核心就是将一个页面拆成一堆独立的,可复用的组件,自上而下的单向数据流的形式将组件串联起来,在使用class类组件时,他自身就有state状态,所以复用起来就很麻烦,官方的解决方案是:使用渲染属性Render Props和高阶组件Higher-OrderComponents,但是这两种方式会增加代码的层级关系,所以还是hooks比肩简洁
2.生命周期中的钩子函数逻辑太乱
一般情况,如果项目较大,网络请求等就会很繁多,在维护项目时就会变得不直观
3.创建组件时,this指向的问题
有时候写了一个无状态的简洁组件,但后期有需求变动,就得改为class类组件,又的很麻烦费时间
二.hooks函数
1.useState (状态) 使用
useState是react自带的一个hooks函数,作用是用来声明状态变量,接收的参数是状态的初始值,返回一个数组,数组第0项就是当前值,第1项时可以改变这个状态值的方法函数,一般都使用ES6解构的方式,将第一个参数与第二个参数解构出来
import { useState } from 'react'
const Count = () => {
// 错误演示:
// if (Math.random() > 0.5) {
// const [loading, setLoading] = useState(false)
// }
// for (let index = 0; index < [].length; index++) {
// const [loading1, setLoading1] = useState(false)
// }
// const handleClick = () => {
// const [loading2, setLoading3] = useState(false)
// setCount(count + 1)
// }
const [count, setCount] = useState(0)
const [loading, setLoading] = useState(false)
const handleClick = () => {
setCount(count + 1)
}
return (
<div>
<h1>计数器:{count}</h1>
<button onClick={handleClick}>+1</button>
</div>
)
}
export default function App() {
return (
<div>
<Count></Count>
</div>
)
}
2.useEffect (副作用函数) 使用
useEffect副作用函数,有两个参数,第一个参数是一个回调函数,在这里执行逻辑判断,第二个参数是一个数组,表示依赖项,useEffect函数只执行一次,但有时候当数据发生变化的时候,需要再次执行,就需要用到第二个依赖参数,当参数发生改变时,就会再次执行当前函数
import { useState, useEffect } from 'react'
const Count = () => {
const [count, setCount] = useState(0)
const [loading, setLoading] = useState(false)
// 第二个参数:表示 effect 的依赖项,
// 也就是说:只有在数组中的 依赖项 改变时 effect 回调才会执行
useEffect(() => {
console.log('count', count)
document.title = `点击了 ${count} 次`
}, [count])
// }, [count, loading])
const handleClick = () => {
setCount(count + 1)
}
return (
<div>
<h1>计数器:{count}</h1>
<button onClick={handleClick}>+1</button>
<hr />
<div>{loading ? '加载中' : '加载完成!!!'}</div>
<button onClick={() => setLoading(!loading)}>切换loading</button>
</div>
)
}
export default function App() {
return (
<div>
<Count></Count>
</div>
)
}
useEffect与useLayoutEffect区别:
推荐使用useEffect,他会在页面DOM树以及渲染完成后执行,性能会更高,而useLayoutEffect是在DOM树更新完成后执行,会阻塞页面渲染,但如果只做DOM修改就使用useLayoutEffect,因为这样做出的更改会一起被渲染,只有一次回流,重绘的代价。
3.useCallback (记忆函数) 使用
防止组件重新渲染,导致方法重新被创建,起到缓存作用,只有第二个参数变化了,才重新声明一次,如果第二个依赖参数为空,则始终使用当前记忆的参数值,不会重新读取
4.useMemo (记忆组件) 使用
等价于useCallback,他会执行第一个函数并将结果返回,与vue的计算属性基本一致,会返回一个结果,并进行缓存
5.useRef (保存引用值) 使用
类似于React.creactRef(),绑定谁就能获取谁,使用ref绑定useRef,可以绑定标签,组件等,通过useRef可以在hooks函数中保存变量,
6.useContext 和useReducer 使用
useContext 跨级通讯,如果想要组件之间共享状态,可以使用
useContext
。React 的Context API
是一种在应用程序中深入传递数据的方法,使用
Context
,首先顶层先声明Provier
组件,并声明value
属性,接着在后代组件中声明Consumer
组件,这个Consumer
子组件,只能是唯一的一个函数,函数参数即是Context
的负载。如果有多个Context
,Provider
和Consumer
任意的顺序嵌套即可。useReducer 接收两个参数,第一个参数:reducer函数,第二个参数:初始化的state,返回值为最新的state和dispatch函数(用来触发reducer函数,计算对应的state)
7.自定义hooks
当你在一个项目中发现大量类似代码,那就抽离成Hooks
比如我们多个页面有相同的请求方法
// 以use开头 export const useUserData = (category: string[], labelName?: string) => { const [baseTotal, setBaseTotal] = useState<number>(0) useEffect(() => { dealSearchTotal(category, labelName) }, [labelName, category]) const dealSearchTotal = async ( ) => { const data = await getUserData(curCategory, labelName) const { baseTotal, calculateTotal, basicTotal, extTotal } = data setBaseTotal(baseTotal) } // 最后return出想要的数据 return [baseTotal, calculateTotal, basicTotal, extTotal] }