真正吃透React知识链路与底层逻辑, Part4

目前正在学习深入浅出React【真正吃透React知识链路与底层逻辑】共23讲_哔哩哔哩_bilibili

React-hooks的设计动机,使用方法和深层原理

目录

问题集

设计动机

类组件 VS 函数组件

类组件的缺点

函数组件的缺点

Hooks解决的问题

Hooks的问题

为什么要用hooks

使用方法

useState

useEffet

useState深层原理


问题集

  1. hooks所引起的变化并没有访问任何生命周期方法?它是一套完全不同的体系?
  2. 为什么class component的this有时候得不到
  3. useState为什么底层是链表而不是数组?
    1. 猜测是为了更好地unmount组件
  4. 对于其他hooks的源码认识

设计动机

类组件 VS 函数组件

  • 类组件需要继承Component,函数组件是定义函数,不能够继承
  • 类组件能够访问生命周期方法,但是函数组件不行
  • 类组件的操作大量基于this,函数组件中没有this
  • 类组件可以定义和维护state,但是在hooks之前的函数组件没法处理state

类组件的缺点

  • 太过于笨重,难以上手
  • render的状态不一定会与data保持一致,因为this有时候会改变
    • 常见于setTimeout,在timeout的时间内,数据有可能发生了变化,导致render的结果是基于改变了的数据,而不是调用setTimeout的那一刻

函数组件的缺点

  • 没办法处理state,还有生命周期

Hooks解决的问题

  • 为函数组件引入state和生命周期

Hooks的问题

  • 无法替代getSnapshotBeforeUpdate / componentDidCache 等等生命周期
  • 太过于轻量级,有时候没法处理更复杂的业务逻辑
  • 有严格的代码逻辑要求

为什么要用hooks

  1. 告别难用的Class Component
    1. this会有奇怪的表现如下段代码,当我点击按钮的时候程序会报错, 但是如果我将函数的调用额外加一层调用链路就不会报错
      export default class App extends Component {
        state = {
          name: "qwe",
          age: "99",
        };
        changeAge() {
          this.setState({
            age: "100",
          });
        }
        render() {
          return (
            // <button onClick={() => this.changeAge()}> 这样不会报错
            <button onClick={this.changeAge}>
              {/* 这样会报错 */}
              {this.state.name} age is {this.state.age}
            </button>
          );
        }
      }

    2. 生命周期函数
  2. 拆分componentDidMount/didUpdate/willUnmount里面的业务逻辑进useEffect,让逻辑更相关的贴合更近
  3. 更简单重用含有state的逻辑,我们可以将含有state还有一些hooks的逻辑全都单独封装成一个函数,然后哪里需要就调用
  4. 函数组件的编程思想更贴近React的设计理念,也就是UI=f(data)

使用方法

全面的hook API可以进入官方文档,Hook API 索引 – React

useState

const App = ()=>{
    // initialize state a as 1, and get setA which can manipulate a
    const [a, setA] = useState(1);
    
    return <button onClick={()=>setA(a + 1)} />
}
  • 引入了state和修改state的方法
  • 返回一个有两个元素的数组,第一个元素为状态变量,第二个元素为设置这个状态并驱动试图更新的API
  • 一般的命名规则为:[a, setA] = useState(intialValue)

useEffet

const App = ({a,b})=>{
    const [c, ] = useState(123);
    useEffect(()=>{
        // 这个useEffect没有第二个参数(deps数组),这个effect会在每一次函数组件被调用的时候都运行
    })
    useEffect(()=>{
        // 这个useEffect的deps数组是一个空数组,意味着每一次检查deps数组他都不会变化,这个effect只会在这个component第一次被调用的时候运行
        // 一般用例为fetch数据,在全局事件中订阅
    }, [])
    useEffect(()=>{
        return ()=>{
            // useEffect的返回值是一个在这个组件将要被unMount的时候运行的函数
            // 一般可以用来取消订阅
            // 不论deps数组是什么,返回的clean up函数都只会跑一次
        }
    }, anything)
    useEffect(()=>{
        // 这个effect会在a,b,c之中任何一个有变化的时候被调用(包扩第一次)
    },[a,b,c])
}
  • 引入了生命周期
  • 有两个参数
    • 第一个参数是需要执行的sideEffect,函数自身提供mounting和updating的effect,函数返回的另外一个函数提供unmounting的effect
    • 第二个参数是deps数组,这个参数决定了什么时候effect函数会被执行,当有任意的deps数组的元素发生了变化,(对比通过Object.is来完成,可以理解成对于地址的对比)。

useState深层原理

  • 这部分需要深入挖掘,但是目前对fiber架构没有足够的认知,留到未来
  • 通过useState的深层原理做研究,对于别的hooks可以做借鉴,但不一定完全一样,未来可以深究
  • useState
    • 第一次渲染,调用mountState,构建一个state的链表,并渲染
    • 之后的渲染,调用updateSate,依次便利构建好的链表并渲染
    • 如果useState出现在if或者switch里面,这意味着不是链表不会被便利,很可能我们得到的state错位了
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值