「React 进阶」 React 全部 Hooks 使用大全 (包含 React v18 版本 )(中)

简介: 一份 React Hooks 的使用词典

React Hooks.png

一 前言

React hooks是react16.8 以后,react新增的钩子API,目的是增加代码的可复用性,逻辑性,弥补无状态组件没有生命周期,没有数据管理状态state的缺陷。本章节笔者将介绍目前 React 提供的所有 hooks ,介绍其功能类型和基本使用方法。

创作不易,希望屏幕前的你能给笔者赏个,以此鼓励我继续创作前端硬文。🌹🌹🌹

二 hooks 之执行副作用

2.1 useEffect

React hooks也提供了 api ,用于弥补函数组件没有生命周期的缺陷。其本质主要是运用了 hooks 里面的 useEffect , useLayoutEffect,还有 useInsertionEffect。其中最常用的就是 useEffect 。我们首先来看一下 useEffect 的使用。

useEffect 基础介绍:

useEffect(()=>{
   
   
    return destory
},dep)

useEffect 第一个参数 callback, 返回的 destory , destory 作为下一次callback执行之前调用,用于清除上一次 callback 产生的副作用。

第二个参数作为依赖项,是一个数组,可以有多个依赖项,依赖项改变,执行上一次callback 返回的 destory ,和执行新的 effect 第一个参数 callback 。

对于 useEffect 执行, React 处理逻辑是采用异步调用 ,对于每一个 effect 的 callback, React 会向 setTimeout回调函数一样,放入任务队列,等到主线程任务完成,DOM 更新,js 执行完成,视图绘制完毕,才执行。所以 effect 回调函数不会阻塞浏览器绘制视图。

useEffect 基础用法:

/* 模拟数据交互 */
function getUserInfo(a){
   
   
    return new Promise((resolve)=>{
   
   
        setTimeout(()=>{
   
    
           resolve({
   
   
               name:a,
               age:16,
           }) 
        },500)
    })
}

const Demo = ({
   
    a }) => {
   
   
    const [ userMessage , setUserMessage ] :any= useState({
   
   })
    const div= useRef()
    const [number, setNumber] = useState(0)
    /* 模拟事件监听处理函数 */
    const handleResize =()=>{
   
   }
    /* useEffect使用 ,这里如果不加限制 ,会是函数重复执行,陷入死循环*/
    useEffect(()=>{
   
   
       /* 请求数据 */
       getUserInfo(a).then(res=>{
   
   
           setUserMessage(res)
       })
       /* 定时器 延时器等 */
       const timer = setInterval(()=>console.log(666),1000)
       /* 操作dom  */
       console.log(div.current) /* div */
       /* 事件监听等 */
       window.addEventListener('resize', handleResize)
         /* 此函数用于清除副作用 */
       return function(){
   
   
           clearInterval(timer) 
           window.removeEventListener('resize', handleResize)
       }
    /* 只有当props->a和state->number改变的时候 ,useEffect副作用函数重新执行 ,如果此时数组为空[],证明函数只有在初始化的时候执行一次相当于componentDidMount */
    },[ a ,number ])
    return (<div ref={
   
   div} >
        <span>{
   
    userMessage.name }</span>
        <span>{
   
    userMessage.age }</span>
        <div onClick={
   
    ()=> setNumber(1) } >{
   
    number }</div>
    </div>)
}

如上在 useEffect 中做的功能如下:

  • ① 请求数据。
  • ② 设置定时器,延时器等。
  • ③ 操作 dom , 在 React Native 中可以通过 ref 获取元素位置信息等内容。
  • ④ 注册事件监听器, 事件绑定,在 React Native 中可以注册 NativeEventEmitter 。
  • ⑤ 还可以清除定时器,延时器,解绑事件监听器等。

2.2 useLayoutEffect

useLayoutEffect 基础介绍:

useLayoutEffect 和 useEffect 不同的地方是采用了同步执行,那么和useEffect有什么区别呢?

① 首先 useLayoutEffect 是在 DOM 更新之后,浏览器绘制之前,这样可以方便修改 DOM,获取 DOM 信息,这样浏览器只会绘制一次,如果修改 DOM 布局放在 useEffect ,那 useEffect 执行是在浏览器绘制视图之后,接下来又改 DOM ,就可能会导致浏览器再次回流和重绘。而且由于两次绘制,视图上可能会造成闪现突兀的效果。

② useLayoutEffect callback 中代码执行会阻塞浏览器绘制。

useEffect 基础用法:

const DemoUseLayoutEffect = () => {
   
   
    const target = useRef()
    useLayoutEffect(() => {
   
   
        /*我们需要在dom绘制之前,移动dom到制定位置*/
        const {
   
    x ,y } = getPositon() /* 获取要移动的 x,y坐标 */
        animate(target.current,{
   
    x,y })
    }, []);
    return (
        <div >
            <span ref={
   
    target } className="animate"></span>
        </div>
    )
}

2.3 useInsertionEffect

useInsertionEffect 基础介绍:

useInsertionEffect 是在 React v18 新添加的 hooks ,它的用法和 useEffect 和 useLayoutEffect 一样。那么这个 hooks 用于什么呢?

在介绍 useInsertionEffect 用途之前,先看一下 useInsertionEffect 的执行时机。

React.useEffect(()=>{
   
   
    console.log('useEffect 执行')
},[])

React.useLayoutEffect(()=>{
   
   
    console.log('useLayoutEffect 执行')
},[])

React.useInsertionEffect(()=>{
   
   
    console.log('useInsertionEffect 执行')
},[])

打印: useInsertionEffect 执行 -> useLayoutEffect 执行 -> useEffect 执行

可以看到 useInsertionEffect 的执行时机要比 useLayoutEffect 提前,useLayoutEffect 执行的时候 DOM 已经更新了,但是在 useInsertionEffect 的执行的时候,DOM 还没有更新。本质上 useInsertionEffect 主要是解决 CSS-in-JS 在渲染中注入样式的性能问题。这个 hooks 主要是应用于这个场景,在其他场景下 React 不期望用这个 hooks 。

useInsertionEffect 模拟使用:

export default function Index(){
   
   

  React.useInsertionEffect(()=>{
   
   
     /* 动态创建 style 标签插入到 head 中 */
     const style = document.createElement('style')
     style.innerHTML = `
       .css-in-js{
         color: red;
         font-size: 20px;
       }
     `
     document.head.appendChild(style)
  },[])

  return <div className="css-in-js" > hello , useInsertionEffect </div>
}

如上模拟了 useInsertionEffect 的使用。

三 hooks 之状态获取与传递

3.1 useContext

useContext 基础介绍

可以使用 useContext ,来获取父级组件传递过来的 context 值,这个当前值就是最近的父级组件 Provider 设置的 value 值,useContext 参数一般是由 createContext 方式创建的 ,也可以父级上下文 context 传递的 ( 参数为 context )。useContext 可以代替 context.Consumer 来获取 Provider 中保存的 value 值。

const contextValue = useContext(context)

useContext 接受一个参数,一般都是 context 对象,返回值为 context 对象内部保存的 value 值。

useContext 基础用法:

/* 用useContext方式 */
const DemoContext = ()=> {
   
   
    const value:any = useContext(Context)
    /* my name is alien */
return <div> my name is {
   
    value.name }</div>
}

/* 用Context.Consumer 方式 */
const DemoContext1 = ()=>{
   
   
    return <Context.Consumer>
         {
   
   /*  my name is alien  */}
        {
   
    (value)=> <div> my name is {
   
    value.name }</div> }
    </Context.Consumer>
}

export default ()=>{
   
   
    return <div>
        <Context.Provider value={
   
   {
   
    name:'alien' , age:18 }} >
            <DemoContext />
            <DemoContext1 />
        </Context.Provider>
    </div>
}

3.2 useRef

useRef 基础介绍:

useRef 可以用来获取元素,缓存状态,接受一个状态 initState 作为初始值,返回一个 ref 对象 cur, cur 上有一个 current 属性就是 ref 对象需要获取的内容。

const cur = React.useRef(initState)
console.log(cur.current)

useRef 基础用法:

useRef 获取 DOM 元素,在 React Native 中虽然没有 DOM 元素,但是也能够获取组件的节点信息( fiber 信息 )。

const DemoUseRef = ()=>{
   
   
    const dom= useRef(null)
    const handerSubmit = ()=>{
   
   
        /*  <div >表单组件</div>  dom 节点 */
        console.log(dom.current)
    }
    return <div>
        {
   
   /* ref 标记当前dom节点 */}
        <div ref={
   
   dom} >表单组件</div>
        <button onClick={
   
   ()=>handerSubmit()} >提交</button> 
    </div>
}

如上通过 useRef 来获取 DOM 节点。

useRef 保存状态, 可以利用 useRef 返回的 ref 对象来保存状态,只要当前组件不被销毁,那么状态就会一直存在。

const status = useRef(false)
/* 改变状态 */
const handleChangeStatus = () => {
   
   
  status.current = true
}

3.3 useImperativeHandle

useImperativeHandle 基础介绍:

useImperativeHandle 可以配合 forwardRef 自定义暴露给父组件的实例值。这个很有用,我们知道,对于子组件,如果是 class 类组件,我们可以通过 ref 获取类组件的实例,但是在子组件是函数组件的情况,如果我们不能直接通过 ref 的,那么此时 useImperativeHandle 和 forwardRef 配合就能达到效果。

useImperativeHandle 接受三个参数:

  • ① 第一个参数ref: 接受 forWardRef 传递过来的 ref。
  • ② 第二个参数 createHandle :处理函数,返回值作为暴露给父组件的 ref 对象。
  • ③ 第三个参数 deps : 依赖项 deps ,依赖项更改形成新的 ref 对象。

useImperativeHandle 基础用法:

我们来模拟给场景,用useImperativeHandle,使得父组件能让子组件中的input自动赋值并聚焦。

function Son (props,ref) {
   
   
    console.log(props)
    const inputRef = useRef(null)
    const [ inputValue , setInputValue ] = useState('')
    useImperativeHandle(ref,()=>{
   
   
       const handleRefs = {
   
   
           /* 声明方法用于聚焦input框 */
           onFocus(){
   
   
              inputRef.current.focus()
           },
           /* 声明方法用于改变input的值 */
           onChangeValue(value){
   
   
               setInputValue(value)
           }
       }
       return handleRefs
    },[])
    return <div>
        <input
            placeholder="请输入内容"
            ref={
   
   inputRef}
            value={
   
   inputValue}
        />
    </div>
}

const ForwarSon = forwardRef(Son)

class Index extends React.Component{
   
   
    inputRef = null
    handerClick(){
   
   
       const {
   
    onFocus , onChangeValue } =this.cur
       onFocus()
       onChangeValue('let us learn React!')
    }
    render(){
   
   
        return <div style={
   
   {
   
    marginTop:'50px' }} >
            <ForwarSon ref={
   
   node => (this.inputRef = node)} />
            <button onClick={
   
   this.handerClick.bind(this)} >操控子组件</button>
        </div>
    }
}

效果:

8e8c05f0c82c43719079d4db9536abc0_tplv-k3u1fbpfcp-watermark.gif

总结

在下一篇文章中,我们将继续介绍 React Hooks 。

相关文章
|
1天前
|
前端开发 JavaScript 数据格式
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
9 1
|
4天前
|
缓存 前端开发 JavaScript
React Hooks(实例及详解)
【7月更文挑战第2天】React Hooks(实例及详解)
12 3
|
1天前
|
前端开发
react18【系列实用教程】Hooks 闭包陷阱 (2024最新版)含useState 闭包陷阱,useEffect 闭包陷阱,useCallback 闭包陷阱
react18【系列实用教程】Hooks 闭包陷阱 (2024最新版)含useState 闭包陷阱,useEffect 闭包陷阱,useCallback 闭包陷阱
4 0
|
1天前
|
前端开发 JavaScript
react18【系列实用教程】useState —— 声明响应式变量(2024最新版)含useState 的异步更新机制,更新的合并,函数传参获取更新值,不同版本异步更新差异,更新对象和数组
react18【系列实用教程】useState —— 声明响应式变量(2024最新版)含useState 的异步更新机制,更新的合并,函数传参获取更新值,不同版本异步更新差异,更新对象和数组
8 0
|
16天前
|
缓存 前端开发 JavaScript
React Hooks 一步到位
React Hooks 一步到位
|
2月前
|
存储 前端开发 JavaScript
React Hooks 的替代方案有哪些?
【5月更文挑战第28天】React Hooks 的替代方案有哪些?
29 2
|
2月前
|
前端开发 JavaScript 开发者
React Hooks 的应用场景有哪些?
【5月更文挑战第28天】React Hooks 的应用场景有哪些?
22 1
|
2月前
|
前端开发 JavaScript 开发者
React Hooks 是在 React 16.8 版本中引入的一种新功能
【5月更文挑战第28天】React Hooks 是在 React 16.8 版本中引入的一种新功能
34 1
|
2月前
|
前端开发
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
|
2月前
|
前端开发 JavaScript
React Hooks:让你轻松掌握函数组件的状态与管理
React Hooks:让你轻松掌握函数组件的状态与管理