常用React Hooks详解

154 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

使用hooks理由

- 高阶组件为了复用,导致代码层级复杂
- 生命周期的复杂
- 写成functional组件,无状态组件,因为需要状态,又改成class成本高

1.useState(保存组件状态)

const [state,setstate]=useState(initialState)

useState将会返回两个参数,一个是设置的状态,一个是改变这个状态的方法,我们可以使用结构方式获取。 (1).我们可以打印查看useState返回的参数

import React, { useState } from 'react'

export default function Hookscomp(){
   const data = useState([])
   console.log(data)
   
   return (
     <div>hooks</div>
   )
}

1652583923(1).jpg (2).使用方式

import React, { useState } from 'react'

export default function Hookscomp(){
    const [number,setNumber]=useState(1)
    return (
      <>
      <div>{number}</div>
      <button onClick={()=>{setNumber(2)}}>改变Number</button>
      </>
    )
}

2.useEffect(处理副作用)和useLayoutEffect(同步执行副作用)

useEffect 在Dom节点及页面渲染完成后执行,其中依赖处如果为空数组则执行一次,如果设置为某个状态,当这个状态发生改变时,useEffct内副作用将会执行,同一个函数式组将中可以有多个useEffect,return在函数销毁时执行,可用于清除定时器等

useEffect(()=>{
    // effect
    return ()=>{
        //cleanup
    }
},[依赖状态,空数组标识不依赖])

注意:虽然函数式组件中并没有生命周期,但useEffect可以解决一些生命生命周期该做的事情,可以将请求放在useEffect中,并使用空依赖执行一次。 useEffct与和useLayoutEffect区别 简单来说就是调用时机不同,useLayoutEffect和原来componentDidMount & componentDidUpdate一致,在react完成Dom更新后马上同步调用代码,会阻塞页面渲染,而useEffect是会在整个页面渲染完成后才会调用 官方建议使用useEffct 在实际使用过程中如果想避免页面抖动,(在useEffct里修改Dom很有可能会出现),可以把需要操作Dom的代码放在useLayoutEffect中在这里做Dom操作,这些Dom修改会和React做出的更改一起被一次性渲染到屏幕上,只有一次回流、重绘的代价。

3.useCallback(记忆函数)

由于每次状态改变,函数组件将会重新执行,方法将会重新创建,该函数防止因为组件重新渲染,导致方法被重新创建,起到缓存作用,只有第二个参数变化了,才重新声明一次。

var handleClick=useCallback(()=>{
    console.log(name)
},[name])

1.只有name改变后,这个函数才会重新声明一次
2.如果传入空数组,那么就是第一次创建后被缓存,如果name后期改变了,那么得到的还是老的name。
3.如果不传入第二个参数,每次都会重新声明一次,拿到的就是最新的name

4.useMemo(记忆组件-可以当做vue中computed使用)

useCallback的功能完全可以由useMemo所取代,如果你想通过使用useMemo返回一个记忆函数也是完全可以的 唯一的区别:useCallback不会执行第一个参数函数,而是将它返回,而useMemo会执行第一个函数并返回函数执行结果, useCallback适用记忆函数,生成记忆后的函数并传递给子组件使用,而useMemo更适合经过函数计算得到一个确定的值,比如记忆组件

5.useRef(保存引用值)

const myRefs=useRef(null)
<Component ref={myRefs}/>

6.useReducer和useContext(减少组件层级)

父组件引入GlobalContext,并使用GlobalContext.Provider(生产者)

import React from 'react';
import Bus from './day2/bus'
export const GlobalContext=React.createContext()
class Swipers extends Component {
    render(){
        return(
            <GlobalContext.Provider value={
                    {
                        name:'全局context测试',
                    }

                }>
            <Bus />
            </GlobalContext.Provider>
        ) 
    }
}

但获取方式与类组件方式发生了变化,不再使用GlobalContext.Consumer消费者获取而是使用useContext函数获取

     function Demo(){
         const value=useContext(GlobalContext) // 定义好的全局状态
         console.log(value) // value即可获取全局状态
     }

useReducer用法如果有Redux学习经验可以理解为简略版Redux,reducer执行操作,initialState初始值,在reducer函数中根据reducer的type对数据进行操作,而type是由dispatch推入,获取数据则使用state获取。

import React, { useReducer } from 'react'
const reducer=(preState,action)=>{
    const data={...preState}
        switch (action.type){
            case 'add':
                data.number++
                return data;
                case 'increase':
                    data.number--
                    return  data;
                default:
                    return preState;
        }
}
const initialState={
    number:0
}
export default function Hookscomp(){
   const [state,dispatch]=useReducer(reducer,initialState)
    return (
      <>
       <button onClick={()=>{dispatch({type:'increase'})}}>-</button>
       <div>{state.number}</div>
       <button onClick={()=>{dispatch({type:'add'})}}>+</button>
      </>
    )
}

useReducer和useContext联用可以模拟Redux 通过useContext对state及dispatch进行提升,使得子组件可以共享状态及dispatch进行状态修改

import React, { useContext, useReducer } from 'react'

const GlobalContext=React.createContext()

const reducer=(preState,action)=>{
    const data={...preState}
        switch (action.type){
            case 'add':
                data.number++
                return data;
                case 'increase':
                    data.number--
                    return  data;
                default:
                    return preState;
        }
}
const initialState={
    number:0
}
export default function Hookscomp(){
   const [state,dispatch]=useReducer(reducer,initialState)
 
    return (
      <GlobalContext.Provider value={{state,dispatch}}>
       <Child1 />
       <Child2 />
      </GlobalContext.Provider>
    )
}

function Child1(){
    const {state,dispatch}=useContext(GlobalContext)
    return (
        <>
            <button onClick={()=>{dispatch({type:'increase'})}}>-</button>
            <div>{state.number}</div>
        </>
    )
}
function Child2(){
    const {state,dispatch}=useContext(GlobalContext)
    return (
        <>
            <div>{state.number}</div>
            <button onClick={()=>{dispatch({type:'add'})}}>+</button>
        </>
    )
}

7.自定义hooks

必须以use开头,如果不遵循,无法判断某个函数是否包含对内部Hooks的调用,React将无法自动检查你的Hook是否违反了Hook的规则。 示例:

    function useFilter(){
        const [name,setName]=useState() // 定义hooks中可以使用React Hook
        return {
            name
        }
    }
    function HookUse(){
        const {name}=useFilter()
    }