《React设计原理》阅读笔记day1

333 阅读2分钟

阅读《React设计原理》确实给到了我不一样的体验,记得上次从书本上对知识汲取的真实感知还是在高中的时候,也是相当久远了,最近公司给了二百多经费让购买书籍,杂七杂八买了一些,从今天开始打卡阅读,望监督!

首先看到了一个非常贴切的对前端框架实现原理的公式,用简单的公式,初中的数学知识:自变量、因变量、无副作用的因变量、有副作用的因变量完美解释了react的hooks

UI=f(state)

  • state代表当前视图状态
  • f代表框架内部运行机制
  • UI代表宿主环境的视图

React中的自变量与因变量

  • useState:定义组件内部的自变量
  • useReducer:定义组件内部复杂的自变量
  • useMemo:采用缓存的方式,定义组件内部无副作用的因变量
  • useCallback:采用缓存的方式,定义组件内无副作用的因变量,缓存值为函数形式
  • useEffect:定义组件内部有副作用的因变量

接下来就是手写代码环节,来看看react的细粒度更新

image.png

简单实现useState

function useState(value){
    const getter = ()=>value
    const setter = (nextValue)=>value = newValue
    return [getter,setter]
}

简单实现useEffect

对于我们手写的useEffect有如下期待:

  1. useEffect执行后,回调函数立刻执行
  2. 依赖的自变量变化后,回调函数立刻执行
  3. 不需要显式依赖

useState和useEffect属于发布订阅关系

image.png

const effectStack = []
//手写status
function subscribe(effect, subs) {
  //建立订阅关系
  subs.add(effect)
  //建立依赖关系
  effect.deps.add(subs)
}

function cleanup(effect) {
  //从该effect订阅的所有state对应的subs中移除该effect
  for (const subs of effect.deps) {
    subs.delete(effect)
  }
  //将该effect依赖的所有state对应的subs移除
  effect.deps.clear()
}

function useState(value) {
  //保存订阅该state变化的effect
  const subs = new Set()
  const getter = () => {
    //获取当前上下文的effect
    const effect = effectStack[effectStack.length - 1]
    if (effect) {
      //建立订阅发布关系
      subscribe(effect, subs)
    }
    return value
  }
  const setter = (nextValue) => {
    value = nextValue
    //通知所有订阅该state变化的effect执行
    for (const effect of [...subs]) {
      effect.execute()
    }
  }
  return [getter, setter]
}
//手写useEffect


function useEffect(callback) {
  const execute = () => {
    //重置依赖
    cleanup(effect);
    //将当前effect推入栈顶
    effectStack.push(effect);
    try {
      //执行回调
      callback()
    } finally {
      //effect出栈
      effectStack.pop()
    }
  }
  const effect = {
    execute,
    deps: new Set()
  }

  //立即执行一次,建立订阅发布关系
  execute()
}
//手写useMemo
function useMemo(callback) {
  const [s, set] = useState()
  //首次执行callback,初始化value
  useEffect(() => set(callback()))
  return s
}

优点:

  1. 无需显示指名依赖
  2. 由于可以自动跟踪依赖,因此不受 不能在条件语句中声明的hooks限制