React 常用的Hooks(钩子函数)

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不能随便乱用,它有自己的处理逻辑和缓存机制,消耗时间。

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值