Hook是React 16.8.0版本增加的新特性/新语法
可以让你在函数组件中使用 state ,ref 以及其他的 React 特性
State Hook 作用 :让函数组件也可以有state状态, 并进行状态数据的读写操作
在这里说几个细节上的问题:
该函数组件执行次数为 n+1 次, 1 是初始化那一次
函数重新执行按理说初始化的值会一直被覆盖,导致数据不能发生变化
问题 :为什么数据是可以发生变化的?
原因:react底层做了处理,在初始化的时候将初始化的值存了起来,下次
执行的时候使用的是存起来的值
StateHook中修改状态的方法不会去合并对象而是去替换对象,这点和类组件中的setState()不同
import React, { Component } from 'react'
export default function Test (){
/*
调用React.useState(initValue) ,传入的是初始化的值
该方法返回的是一个数组
- 数组中第一个参数为:初始化的值/当前状态的值
- 数组中第二个参数为:操作该状态的方法
*/
const [count,setCount] = React.useState(0)
const [person,setPerson] = React.useState([
{
name:'Jack',
age:18,
id:'001'
}
])
const [obj,setObj] = React.useState({name:'Jane',age:52})
const add = () =>{
// 第一种写法,参数为非函数值
// 直接指定新的状态值, 内部用其覆盖原来的状态值
setCount(count+1)
}
const subtract = () =>{
// 第二种写法,参数为函数
// 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
setCount(count=>count-1)
}
const addPerson = () =>{
setPerson((person)=>{
let obj = {id:'002',name:'Mark',age:12}
return [obj,...person]
})
}
/*
在这里需要注意:它和类组件的中的setState不同
不会进行合并对象而是去替换对象
*/
const changeName = () =>{
setObj((obj)=>{
return Object.create(Object.assign(obj,{name:'Lili'}))
})
}
return (
<div>
<h2>当前求和为:{count}</h2>
<h2 onClick={changeName}>{obj.name} --- {obj.age}</h2>
<button onClick={add}>点我+1</button>
<button onClick={subtract}>点我-1</button>
<button onClick={addPerson}>添加人员</button>
{
person.map((item)=>{
return <li key={item.id}>{item.name} --- {item.age}</li>
})
}
</div>
)
}
Effect Hook 作用: 可以在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
React中的副作用操作:
1. 发ajax请求数据获取
2. 设置订阅 / 启动定时器
3. 手动更改真实DOM
4. 清除定时器
useEffect Hook 可以看做如下三个生命周期组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()
第一种写法:
React.useEffect(()=>{
// 相当于 componentDidUpdate()
// 监视所有的数据一旦数据发生变化就调用该函数
console.log('@');
})
第二种写法:
React.useEffect(()=>{
// 相当于 componentDidUpdate()
// 第二个函数可以传入一个数组,数组内可以指定监视某个属性
// 监视的属性一旦发生变化就调用该函数
console.log('@');
},[count])
第三种写法:
React.useEffect(()=>{
// 如果只写一个数组那么就表示谁也不监视
// 只在初始化的时候执行一次,相当于componentDidMount()
console.log('@');
},[])
第四种写法:
React.useEffect(()=>{
return ()=>{
// 该函数中只有在组件将要被卸载的时候才会执行
// 相当于componentWillUnmount()
console.log('@');
}
},[])
Ref Hook 作用 :可以在函数组件中存储/查找组件内的标签或任意其它数据
语法:const refContainer = React.useRef()
用法和React.createRef()
一样
import React, { Component } from 'react'
export default function Demo(){
// 创建一个存放ref的容器
const inpRef = React.useRef()
const tip = () =>{
alert(inpRef.current.value)
}
return (
<div>
<input type="text" ref={inpRef} />
<button onClick={tip}>alert</button>
</div>
)
}
作用:防止组件重新渲染时,导致函数重新进行创建,对函数起到缓存作用
根据下面这个案例,不管是修改数值还是修改名字,只要一修改那么整个函数式组件就会重新被渲染, 函数就会被重新创建声明,useCallBack( )
就是为了解决这个问题而诞生,可以提高性能优化
import React, { useState, useCallback } from 'react'
export default function CallBack() {
const [count, setCount] = useState(0)
const [name,setName] = useState('Jack')
/*
useCallback()可以传入两个参数
- 第一个参数就是我们所写的逻辑
- 第二个参数就是逻辑中所依赖的属性
函数在第一次创建的时候就被缓存,只有所依赖的属性发生
变化才会重新创建声明函数
*/
const handleAdd = useCallback(
() => {
setCount(count + 1 )
},
[count]
)
const modifyName = useCallback(
() =>{
setName('LiHua')
},[]
)
return (
<div>
<h2>当前的值为:{count}</h2>
<button onClick={() => { handleAdd() }}>add</button>
<h2>{name}</h2>
<button onClick={modifyName}>点击修改名字</button>
</div>
)
}
useCallback的功能完全可以由useMemo所替代
那么它们之间的区别在于哪里呢?
写法
useCallback(fn,[attr])
useMemo(()=> fn, [attr])
用法
useCallback
不会执行第一个参数中的函数,而是直接将该函数返回,而useMemo
会执行第一个参数中的函数并且将函数执行的结果返回给你,学过Vue的小伙伴应该就知道这个相当于Vue中计算属性
使用场景
useCallback常用于记忆事件函数,而useMemo更适合通过一个函数计算得到一个确定的值
import axios from 'axios'
import React,{useState,useMemo,useEffect,useCallback} from 'react'
export default function UseMemo() {
const [inpVal,setInpVal] = useState('')
const [list,setList] = useState([])
useEffect(()=>{
axios({
url:'https://m.maizuo.com/gateway?cityId=310100&ticketFlag=1&k=5006381',
headers:{
'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"1660449552376256314998785","bc":"310100"}',
'X-Host': 'mall.film-ticket.cinema.list'
}
}).then((value)=>{
setList(value.data.data.cinemas)
}).catch((error)=>{
console.log(error);
})
},[])
// 处理搜索
const handleSearch = useCallback(
(e) =>{
setInpVal(e.target.value)
},[]
)
// 筛选符合条件的内容
const filterData = useMemo(()=>{
return list.filter((item)=>{
return item.name.toUpperCase().includes(inpVal.toUpperCase()) || item.address.toUpperCase().includes(inpVal.toUpperCase())
})
},[list,inpVal])
return (
<div>
<input type="text" onChange={handleSearch}/>
<ul>
{
filterData.map((item)=>{
return (
<li key={item.cinemaId}>
<h3>{item.name}</h3>
<h5>{item.address}</h5>
</li>
)
})
}
</ul>
</div>
)
}
作用:适用于祖先和后代间通信
import React ,{createContext,useContext}from 'react'
// 第一步: 创建context对象
const GlobalContext = createContext()
export default function UseContextTest() {
return (
// 第二步: GlobalContext.Provider包裹祖先,让他成为供应商
// value属性:传入数据
<GlobalContext.Provider value={{
info:'这是祖先传递的消息',
message:()=>{
console.log('这是祖先传递的方法');
}
}}>
<div style={{padding:'10px',background:'green'}}>
<h2>我是祖先</h2>
<Father></Father>
</div>
</GlobalContext.Provider>
)
}
function Father() {
return (
<div style={{padding:'10px',background:'pink'}}>
<h2>我是儿子</h2>
<Son></Son>
</div>
)
}
function Son() {
// 第三步:通过useContext(context对象)
const value = useContext(GlobalContext)
return (
<div style={{padding:'10px',background:'red'}}>
<h2>我是孙子</h2>
<h4>{value.info}</h4>
<h4>{value.message()}</h4>
</div>
)
}
作用:用于状态管理,和redux作用一样,也是根据redux所创造出来的hook,那么它需要配合useContext一起使用
import React,{useReducer} from 'react'
export default function UseReducer() {
const initState = {count:0}
/*
reducer处理函数可以接收到两个参数
- 第一个参数:之前状态的值
- 第二个参数:所派发的action
- action是一个对象里面存放type和data
*/
const reducer = (previousState=initState,action)=>{
const {type,data} = action
switch (type) {
case 'plus':
return {count:previousState.count + data}
case 'subtract':
return {count:previousState.count - data}
default:
return previousState
}
}
/*
useReducer可以接收到两个参数
- 第一个参数:总状态
- 第二个参数:dispatch用来派发action
useReducer需要传入到两个参数
- reducer:处理函数
- initState:初始化状态
*/
const [state,dispatch] = useReducer(reducer,initState)
return (
<div>
<h2>当前的值为:{state.count}</h2>
<button onClick={()=>{
dispatch({type:'plus',data:1})
}}> +1 </button>
<button onClick={()=>{
dispatch({type:'subtract',data:1})
}}> -1 </button>
</div>
)
}
自定义 Hook 是一个函数,其名称以 “use
” 开头,函数内部可以调用其他的 Hook。
其实本质上就是提取公共部分的逻辑,对其进行函数封装
import {useState,useEffect} from 'react'
import axios from 'axios'
export default function useGetData() {
const [getData,setData] = useState([])
useEffect(()=>{
axios({
url: 'https://m.maizuo.com/gateway?cityId=350600&ticketFlag=1&k=8644263',
headers: {
'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"1660449552376256314998785","bc":"350600"}',
'X-Host': 'mall.film-ticket.cinema.list'
}
}).then((value) => {
setData(value.data.data.cinemas)
}).catch((error) => {
console.log(error)
})
},[])
return getData
}
以上就是今天要讲的内容,希望对大家有所帮助!!!