Hooks 可以帮助在组件中使用不同的 React 功能。所有的Hooks函数只能在函数组件中使用,在类组件中使用会报错,下面介绍几个常用的Hooks函数:
useState:目的是在函数组件中使用状态,并且后期基于状态的修改,可以让组件更新。基本用法如下所示:
import {useState} from 'react'
const Count=()=>{
//num存储的是状态值,setNum存储的是修改状态的方法,0是初始状态值
let [num,setNum]=useState(0)
return(
<div>
<p>{num}</p>
<Button onClick={()=>{setNum(num+1)}}>加1</Button>
</div>
)
}
export default Count
这样一个简单的修改状态的方法就完成了,当然我们也可以把修改状态的方法单独写
import {useState} from 'react'
const Count=()=>{
//num存储的是状态值,setNum存储的是修改状态的方法,0是初始状态值
let [num,setNum]=useState(0)
const handleNum=()=>{
setNum(num+1)
}
return(
<div>
<p>{num}</p>
<Button onClick={handleNum}>加1</Button>
</div>
)
}
export default Count
函数组件的每一次渲染(或者是更新),都会把函数重新执行。产生一个全新的(私有上下文),内部的代码也需要重新执行,涉及的函数需要重新构建{这些函数的作用于执行函数的上下文,是每一次执行Count产生的闭包。
useEffect和useLayoutEffect:在函数组件中,模拟使用生命周期函数,基本用法如下所示:
/* 1.useEffect(callback回调函数)
第一次渲染完毕后会执行callback,在组件每一次更新完毕后,也会执行callback*/
useEffect(() => {
console.log(useEffect, 'useEffect')
})
/* 2.useEffect(callback回调函数,[])
只有第一次渲染完毕后才会执行callback,之后视图更新,callback都不再执行*/
useEffect(() => {
console.log(useEffect, 'useEffect')
}, [])
/* 3.useEffect(callback回调函数,[依赖的状态(可以多个状态)])
第一次渲染完毕后会执行callback,
当依赖的状态(多个状态中的一个发生变化也会)发生变化后也会执行callback,
如果依赖的状态没有发生变化,在组件更新的时候,callback不会执行
以下useEffect依赖的状态是count,那么当count变化后,组件进行更新,callback也会执行*/
useEffect(() => {
console.log(useEffect, 'useEffect')
}, [count])
/* useEffect如果设置返回值,则返回值必须是一个函数(代表组件销毁时触发)*/
useEffect(() => {
return () => {
//这里返回的函数,会在组件销毁的时候执行,如果组件更新,会把上一次返回的函数执行
console.log(useEffect, 'useEffect')
}
})
useEffect(() => {
return () => {
//依赖的状态,依赖的状态变化,组件更新。这里获取的是上一次的状态值
console.log(count, 'useEffect')
}
},[count])
注:useEffect必须在函数的最外层上下文中调用,不能把其嵌入到条件判断、循环等操作语句中。useLayoutEffect的使用方法和useEffect相同,两者都可以获取到DOM元素。useLayoutEffect 会阻塞浏览器渲染真实DOM,因为它在真实DOM还没有渲染的时候(也就是还在虚拟DOM的时候)就会进行视图更新,然后再和上一次的虚拟DOM合并在一起渲染成真实DOM。而useEffect是在真实DOM渲染之后进行视图更新的。因此useLayoutEffect会优先于useEffect执行。
useRef:
我们基于ref可以做的事情:
赋值给一个标签:获取DOM元素
赋值给一个类子组件:获取子组件实例(可以基于实例调用子组件中的属性和方法等)
class Child extends React.Component{
state={
x:1000
}
render(){
return <view>
{this.state.x}
</view>
}
}
const Demo = () => {
let x = useRef(null)
useEffect(() => {
console.log(x.current, '获取到子组件Child实例')
})
return (
<View>
<Child ref={x} />
</View >
)
}
export default Demo
赋值给一个函数子组件:报错(需要配合React.forwardRef实现ref转发,获取子组件中的某个DOM元素)
const Child = React.forwardRef((props, ref) => {
return <View>
<Text ref={ref}>child组件</Text>
</View>
})
const Demo = () => {
let x = useRef(null)
useEffect(() => {
//拿到子组件的<Text>child组件</Text>
console.log(x.current)
})
return (
<View>
<Child ref={x} />
</View >
)
}
export default Demo
ref在类组件当中的使用方法:
1.ref='box':this.refs.box 获取(不推荐使用,严格模式下会报错)
2.ref={x=>this.box=x}:this.box获取
3.this.box=React.createRef():创建一个ref对象 <h2 ref={this.box}> this.box.current获取DOM元素
ref在函数组件当中的使用方法:
1.基于‘ref={函数}’的方式,可以把创建的DOM元素(或者子组件的实例)赋值给一个变量
const Demo=()=>{
let box;
useEffect(()=>{
console.log(box)
},[])
return(
<View>
<Text ref={x=>box=x}></Text>
</View>
)
}
export defalut Demo;
2.使用React.createRef()创建一个ref对象
const Demo=()=>{
let box=React.createRef();
useEffect(()=>{
console.log(box)
},[])
return(
<View>
<Text ref={box}></Text>
</View>
)
}
export defalut Demo;
3.使用Hooks函数useRef()创建一个ref对象
const Demo=()=>{
let box=useRef();
useEffect(()=>{
console.log(box)
},[])
return(
<View>
<Text ref={box}></Text>
</View>
)
}
export defalut Demo;
useRef在每一次组件更新的时候,再次执行useRef方法的时候,不会创建新的ref对象,获取到的还是第一次创建的ref对象。createRef在每一次组件更新的时候,都会重新创建一个ref对象,比较浪费性能。类组件中只能使用React.createRef()创建ref对象,为了保证性能,在函数组件中,应该使用useRef()创建ref对象(注:在类组件中,每次组件更新,只是把render方法重新执行)
useImperativeHandle:useImperativeHandle应当与forwardRef一起使用,useImperativeHandle在函数组件中可以向外暴露一些指定的内容:
const Child = React.forwardRef((props, ref) => {
const submit=()=>{
}
useImperativeHandle(ref,()=>{
//这里返回的内容在父组件Demo都可以拿到
return{
submit
}
})
return <View>
<Text>child组件</Text>
</View>
})
const Demo = () => {
let x = useRef(null)
useEffect(() => {
console.log(x.current, '获取到子组件的submit方法')
})
return (
<View>
<Child ref={x} />
</View >
)
}
export default Demo
useMemo:useMemo(callback回调函数,[依赖值]),组件第一次渲染的时候会执行,后面只有当依赖的状态(多个状态的一个发生变化也会)发生变化后才会执行callback,如果依赖的状态没有变化,callback不会重新执行。useMemo具有计算缓存的效果,可以优化性能,减少不必要的计算。
useCallback:const f1=useCallback(callback回调函数,[依赖值]),组件第一次渲染的时候useEffect执行,创建一个函数callback,赋值给f1。组件后续每一次更新,判断依赖的状态是否改变,如果改变,则重新创建新的函数堆并赋值给f1,如果没有改变,则f1获得的一直是之前的函数堆。(依赖值没有设置的话,f1获得的一直是第一渲染创建的callback函数)。useCallback不能随便乱用,它有自己的处理逻辑和缓存机制,消耗时间。