Hook
这篇文章我们来聊一聊的React中的hook?
1.什么是Hook呢?
hooks我们可以简单地理解为React为我们提供的一些api,来供我们使用。如果大家学习过Vue.js3,就会发现Vue3提供的api与React中的hook中api使用方式非常类似。
下面来看看hook中的api有哪些?
2.Hook api
2.1 useState
这个api的作用主要是设置数据 || 绑定数据的! 它的参数主要有两种形式 : 数据 || 回调函数
绑定数据用法:
父组件
import React, { useState } from 'react'
import Home from './component/Home'
export default function App() {
let [data, setData] = useState(["吕德华", "东星耀阳"])
console.log(data);
const handleData = (val) => {
let arr = [val, ...data]
setData(arr)
}
return (
<>
<p>App组件</p>
{data}
<button onClick={() => handleData("北幕")}>CLICK ME</button>
<hr />
<Home data={data} setData={setData}></Home>
</>
)
}
子组件
import React from 'react'
export default function Home({ data, setData }) {
const handleData = (val) => {
let arr = [val, ...data]
console.log(arr);
setData(arr)
}
return (
<>
<p>Home组件数据</p>
<hr />
{data}
<button onClick={() => handleData("大厂")}>CLICK ME</button>
</>
)
}
绑定回调函数用法:
import React, { useState } from 'react'
import Home from './component/Home'
export default function App() {
let [data, setData] = useState(() => {
return ['吕德华']
})
console.log(data);
const handleData = (val) => {
let arr = [val, ...data]
setData(arr)
}
return (
<>
<p>App组件</p>
{data}
<button onClick={() => handleData("北幕")}>CLICK ME</button>
<hr />
<Home data={data} setData={setData}></Home>
</>
)
}
这个时候的绑定的值就是return返回的值,回调函数的用法主要是用来处理一些数据结构和数据类型,然后再进行返回。
2.2 useRef
用于获取dom节点,class类实例对象。注意是一一对应的用法:创建一个使用一个。
import React, { useState, useRef } from 'react'
import Home from './component/Home'
export default function App() {
const myRef = useRef()
let [data, setData] = useState(() => {
return ['吕德华']
})
console.log(data);
const handleData = (val) => {
console.log(myRef.current.innerText);
let arr = [val, ...data]
setData(arr)
}
return (
<>
<p ref={myRef}>App组件</p>
{data}
<button onClick={() => handleData("北幕")}>CLICK ME</button>
<hr />
<Home data={data} setData={setData}></Home>
</>
)
}
2.3 useContext
主要用于跨组件传值。
步骤
创建context ===> 包裹要传值的组件 = => useContext()
传值的那个组件
import React from 'react'
import Home from './component/Home'
import { createContext } from 'react'
export const context = createContext()
export default function App() {
return (
<context.Provider value={{ msg: '1234' }}>
<Home></Home>
</context.Provider>
)
}
接受值的那个组件
import React from 'react'
import Home from './component/Home'
import { createContext } from 'react'
export const context = createContext()
export default function App() {
return (
<context.Provider value={{ msg: '1234' }}>
<Home></Home>
</context.Provider>
)
}
如果想要规范的写法,可以另设一个文件夹,专门用来写hooks的这些用法。
2.4 useCallback
这个api主要用于性能优化,用于存储函数不会被重新创建。函数组件重新执行的时候会重新创建内部所有的函数。
-
存储函数不会被删除
-
防止子组件进行不必要渲染, 父组件传递函数不要进行重新创建传递
useCallback(callback,依赖项)
callback 返回的储存函数
依赖项 选择缓存方式,
1. 不写,每次函数重新执行都会重新创建改函数
2. [],初始时执行一次,后续不在更新,就没有办法获取到新的useState的数据
3. [数据] => 选择性更新(选择性重新创建) => 选择的数据发变化,函数重新创建(该回调函数仅在某个依赖项改变时才会更新) , 获取新的useState的数据 返回的是函数,第一个函数不会执行
应用场景
一个函数里面不可能只有一个数据,当函数里面有多个数据的时候。可根据某个依赖数据选择是否对应改变,而不用每次改变一个数据就重新创建所有的函数,这样会十分地浪费性能。
import React, { useCallback, useState } from 'react'
let set = new Set();
export default function App() {
let [data, setData] = useState(0)
let [qwe, setqwe] = useState(100)
const handleData = useCallback(() => {
setData(data + 1)
})
set.add(handleData)
const handleQwe = useCallback(() => {
setqwe(qwe + 1)
})
set.add(handleQwe)
console.log(set);
return (
<>
data--{data}
<hr />
qwe--{qwe}
<hr />
<button onClick={handleData}>点我处理data</button>
<button onClick={handleQwe}>点我处理qwe</button>
</>
)
}
2.5 useMemo
用于存储数据的(计算得出的值进行存储)
useMemo(callback,依赖项) 返回数据
依赖项 选择缓存方式,
1. 不写,每次函数重新执行都会重新创建改函数
2. [],初始时执行一次,后续不在更新,就没有办法获取到新的useState的数据
3. [数据] => 选择性更新(选择性重新创建) => 选择的数据发变化,函数重新创建,获取新的useState的数据
用法和useCallback一模一样,这里不做过多演示!
2.6 useReducer
它是加强版的useState,本质还是用于存储数据的,操作数据的。但是在这个里面,他处理的逻辑可以更复杂。相当于一个小型的仓库,用来存放一些复杂的逻辑!!!
const [state,dispatch]=useReducer(reducer,init)
reducer(prevState,action)
第一个参数是上一次的状态,第二个参数是行为。
例如代码如下:
import React, { useReducer } from 'react'
let init = {
num: 0
}
let reducer = (prevState, actions) => {
//第一个参数:
//初始的时候,是init里面的函数。后面是上一次返回的参数
// actions是行为 触发的行为
// console.log(prevState.num);
// console.log(actions);
if (actions.type === 'add') {
return { num: prevState.num + 1 }
}
if (actions.type === 'sub') {
return { num: prevState.num - 1 }
}
}
export default function App() {
let [{ num }, dispatch] = useReducer(reducer, init)
// console.log(num, dispatch);
return (
<div>
<h1>App计数器----{num}</h1>
<button onClick={() => dispatch({ type: 'add' })}>ADD</button >
<button onClick={() => dispatch({ type: "sub" })}>SUBLINE</button>
</div>
)
}
使用useReducer的好处:不用写多个函数,传入类型即可,可以处理一些较为复杂的逻辑!!!
2.7 useEffect
首先,我们要知道ajax在react中是什么时候发送请求。通过实验,我们发现,如果我们在函数组件中使用ajax发送请求的话,这个发送请求将会无限循环地执行下去!下面我们来看一段代码:
import React, { useState } from 'react'
import axios from 'axios'
export default function App() {
let [arr, setArr] = useState([])
axios.get("http://jsonplaceholder.typicode.com/posts?userId=2&name=kaola&age=18")
.then(({ data }) => {
setArr(data)
console.log('11111');
})
return (
<div>
{
arr.map(item => {
return (
<p key={item.id}>{item.title}</p>
)
})
}
</div>
)
}
这段代码,我们打开控制台就会发现,他在一直无限循环地打印。因为,setArr会重新更新视图,而重新更新视图又要重新执行这个函数组件。
使用方法:
useEffect(callback,依赖项) 用于处理副作用;
callback
依赖项
1. 不写,每次函数重新执行都会重新创建
2. [],初始时执行一次,后续不在执行
3. [数据] => 选择性执行 =>
根据选择的数据发变化,重新执行,
初始时会执行
这个第三项的典型用法,就是作为分页的时候,将数据传过去。
import React, { useState, useEffect } from 'react'
import axios from 'axios'
export default function App() {
let [arr, setArr] = useState([])
useEffect(() => {
axios.get("http://jsonplaceholder.typicode.com/posts?userId=2&name=kaola&age=18")
.then(({ data }) => {
setArr(data)
console.log('11111');
})
}, [])
return (
<div>
{
arr.map(item => {
return (
<p key={item.id}>{item.title}</p>
)
})
}
</div>
)
}
这样的话,就只会打印一次。
3.自定义hook
什么是自定义hook?
顾名思义,自定义hook就是我们自己定制的函数。
自定义hook有什么作用呢?
复用react,抽离react。
-
限制特点:
-
1.自定义函数(hook)必须以use开头,将会以hook文件进行解析。这里有个命名规范。函数组件首字母大写表示组件,小写是函数,use是hooks。
2.hook只能在函数组件和use函数中使用
3.hooks方法函数组件和use函数中进行使用
4.函数内部的最顶层使用,不能在循环,条件判断,子函数等使用
分离之后的代码
hooks/handleChoose.js
import { useState } from "react"
export const useHandleData = (value) => {
//value在这里只能传递数组
let [data, setData] = useState(value)
let handleAdd = (value1) => {
setData(data.filter((item) => item === value1))
}
let handleDel = (value1) => {
setData(data.filter((item) => {
return item !== value1
}))
}
return [data, handleAdd, handleDel]
}
App.js
import React from 'react'
import { useHandleData } from './hooks/hookChoose'
export default function App() {
let [arr, handleAdd, handleDel] = useHandleData(['朱雀', 'YY', '路遥', '锦鲤'])
return (
<>
<h1>App组件记事本</h1>
{
arr.map(item => {
return <li key={item}>喜欢:{item}--<button onClick={() => handleAdd(item)}>确定</button><button onClick={() => handleDel(item)}>删除</button></li>
}
)
}
</>
)
}
分离之前的代码:
import React, { useState } from 'react'
export default function App() {
let [arr, setArr] = useState(['朱雀', 'YY', '路遥', '锦鲤'])
let handleAdd = (value) => {
setArr(arr.filter((item) => item === value))
}
let handleDel = (value) => {
setArr(arr.filter((item) => {
return item !== value
}))
}
return (
<>
<h1>App组件记事本</h1>
{
arr.map(item => {
return <li key={item}>喜欢:{item}--<button onClick={() => handleAdd(item)}>确定</button><button onClick={() => handleDel(item)}>删除</button></li>
}
)
}
</>
)
}
显然,分离后比分离前逻辑更加清晰!