React hooks使用与实现原理剖析


1. React hooks介绍

React Hooks是用来做什么的?

对函数型组件进行增强,让函数型组件可以存储状态,可以拥有处理副作用的能力,让开发者在不适用类组件的情况下,实现相同的功能。

类组件的不足(Hooks要解决的问题)

  1. 缺少逻辑复用机制

    为了复用逻辑增加无实际渲染效果的组件,增加了组件层级显示十分臃肿,增加了调试的难度以及运行效率的降低

  2. 类组件经常会变得很复杂难以维护

    将一组相干的业务逻辑拆分到了多个生命周期函数中,在一个声明周期函数内存在多个不相干的业务逻辑

  3. 类成员方法不能保证this指向的正确性

2. React hooks使用

Hooks意思为钩子,React Hooks就是一堆钩子函数,React通过这些钩子函数对函数型组件进行增强,不同的钩子函数提供了不同的功能。

useState()

  1. 接收唯一的参数即状态初始值,初始值可以使任意数据类型
  2. 返回值为数组,数组中存储状态值和更改状态值的方法,方法名称约定以set开头,后面加上状态名称
  3. 方法可以被调用多次,用以保存不同状态值
  4. 参数可以是一个函数,函数返回什么,初始状态就是什么,函数只会被调用一次,用在初始值是动态值的情况

细节:

  • 参数为函数时只会被调用一次,用在初始值是动态值的情况
  • 调用set方法时也可以传递一个值或者函数,函数有一个形参就是我们的状态值,函数返回值就是我们要修改的值
  • set方法本身是异步的
import React, {
    useState } from 'react'

export default function Demo(props) {
   
    // 这样写的话每次被渲染的时候都会执行没有意义的props.count
    // const propsCount = props.count || 0 
    // 建议这样写,每次渲染的时候就只会执行一次了
    const [count, setCount] = useState(() => {
   
        return props.count || 0
    })
    function click () {
   
        // setCount(count + 1)
        setCount(count => {
   
            const newCount = count + 1
            // 因为异步,所以写在这里
            document.title = newCount
            return newCount
        })
        // setCount异步 拿不到最新的newCount
        // document.title = newCount
    }
    return <div>
        <span>{
   count}</span>
        <button onClick={
   click}>+ 1</button>
    </div>
}

useReducer

useReducer是另一种让函数组件保存状态的方式。

import React, {
    useReducer } from 'react'

function reducer (state, action) {
   
    switch (action.type) {
   
        case 'increment':
            return state + 1;
        case 'decrement':
            return state - 1;
        default:
            return state
    }
}

export default function Demo(props) {
   
    const [count, dispatch] = useReducer(reducer, 0)

    return <div>
        <span>{
   count}</span>
        <button onClick={
   () => dispatch({
   type: 'increment'})}>+ 1</button>
        <button onClick={
   () => dispatch({
   type: 'decrement'})}>- 1</button>
    </div>
}

useContext

在跨组件层级获取数据时简化获取数据的代码。

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

const countContext = createContext()

export default function Demo(props) {
   
    return <countContext.Provider value={
   100}>
        <Foo />
    </countContext.Provider>
}

function Foo () {
   
    const count = useContext(countContext)
    return <div>{
   count}</div>
}

// function Foo () {
   
//     return <countContext.Consumer>
//         {
   
//             value => {
   
//                 return <div>{value}</div>
//             }
//         }
//     </countContext.Consumer>
// }

useEffect

让函数型组件拥有处理副作用的能力,类似声明周期函数

  1. useEffect执行时机,可以把useEffect看做componentDidMount,componentDidUpdate和componentWillUnmount这三个函数的组合

    useEffect(() => {}) => componentDidMount,componentDidUpdate

    useEffect(() => {}, []) => componentDidMount

    useEffect(() => () => {}) => componentWillUnmount

  2. useEffect使用方法,例如组件加载的时候添加事件,设置定时器

  3. useEffect解决的问题

    • 按照用途将代码进行分类(将一组相干的业务逻辑归置到了同一个副作用函数中)
    • 简化重复代码,使组件内部代码更加清晰,例如将componentDidMount,componentDidUpdate的代码合并在一起了
  4. 只有指定数据发生变化时触发effect

    useEffect(() => {
         
    	document.title = count
    }, [count])
    
  5. useEffect结合异步函数,useEffect中的参数函数不能是异步函数,因为useEffect函数要返回清理资源的函数,如果是异步函数就返回了promise,会报错,可以使用IIFE的方式来使用异步函数

    // 使用链式调用的方式
    export default function Demo() {
         
        useEffect(() => {
         
            getData().then(res => {
         
                console.log(res)
            })
        }, [])
        return <div>Demo</div>
    }
    
    // 下面这样async await的方式会报错
    // export default function Demo() {
         
    //     useEffect(async () => {
         
    //         const res = await getData()
    //         console.log(res)
    //     }, [])
    //     return <div>Demo</div>
    // }
    
    // 如果需要使用异步函数,则要像下面这样使用IIFE 
    export default function Demo() {
         
        useEffect(() => {
         
            (async function (){
         
                const res = await getData()
                console.log(res)
            }())
        }, [])
        return <div>Demo</div>
    }
    
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Whoopsina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值