1. 实现 useEffect

本次课程我们来开始实现一下mini-react中的useEffect。我们先来是先最简单的,没有依赖的情况。

在app.js加上useEffect

jsx 复制代码
 React.useEffect(() => {
    console.log('useEffect')
  }, [])

创建函数,先存起来参数

jsx 复制代码
function useEffect(callback, deps) {
    const effctHook = {
        callback,
        deps
    }
}

调用时机

  • 应该在dom的渲染之后,也就是处理完所有的节点之后调用
  • react.js
jsx 复制代码
function commitRoot() {
    deletions.forEach(commitDeletion)
    commitWork(wipRoot.child)
    commitEffectHook()
    currentRoot = wipRoot
    wipRoot = null
    deletions = []
}
​
function commitEffectHook() {
    function run(fiber) {
        if (!fiber) {
            return
        }
        fiber?.effectHook?.callback()
        run(fiber.child)
        run(fiber.sibling)
    }
    run(wipFiber)
}
​
function useEffect(callback, deps) {
    const effectHook = {
        callback,
        deps
    }
    wipFiber.effectHook = effectHook
}
​
const React = {
    render,
    useState,
    useEffect,
    createElement,
    update
}

1.png

增加依赖项count

  • app.jsx
jsx 复制代码
import React from "./core/React.js";
​
function Foo() {
  console.log('fooo')
  const [bar, setBar] = React.useState('bar')
  function handleClick() {
    setBar('bar')
    setCount(c => c + 1)
  }
​
  const [count, setCount] = React.useState(10);
​
  React.useEffect(() => {
    console.log('useEffect')
  }, [count])
​
  return (
    <div>
      {bar}
      {count}
      <button onClick={handleClick}>click</button>
    </div>
  );
}
​
function App() {
  return (
    <div>
      <Foo />
    </div>
  );
}
​
export default App;
  • 更新核心代码react.js
jsx 复制代码
function commitEffectHook() {
    function run(fiber) {
// ...
        if(!fiber.alternate) {
            fiber.effectHook?.callback()
        }else {
            // update
            // deps 有没有发生改变
            const oldEffectHook = fiber.alternate?.effectHook
​
            // some
            const needUpdate = oldEffectHook?.deps.some((oldDep, index) => {
                return oldDep !== fiber.effectHook.deps[index]
            })
​
            needUpdate && fiber.effectHook?.callback()
​
        }
​
// ...
    }
    run(wipFiber)
}

开始实现多个

  • app.jsx
jsx 复制代码
  React.useEffect(() => {
    console.log('init')
  }, [])
​
  React.useEffect(() => {
    console.log('update', count)
  }, [count])
  • react.js
jsx 复制代码
function commitRoot() {
    deletions.forEach(commitDeletion)
    commitWork(wipRoot.child)
    commitEffectHooks()
    currentRoot = wipRoot
    wipRoot = null
    deletions = []
}
​
function commitEffectHooks() {
    function run(fiber) {
        if (!fiber) {
            return
        }
​
        if(!fiber.alternate) {
            fiber?.effectHooks?.forEach((hook) => {
                hook.callback()
            })
        }else {
            // update
            // deps 有没有发生改变
            fiber.effectHooks?.forEach((newHook, index)=> {
                if(newHook.deps.length> 0 ) {
                    const oldEffectHook = fiber.alternate?.effectHooks[index]
​
                    // some
                    const needUpdate = oldEffectHook?.deps.some((oldDep, i) => {
                        return oldDep !== newHook.deps[i]
                    })
​
                    needUpdate && newHook.callback()
                }
            })
        }
​
        run(fiber.child)
        run(fiber.sibling)
    }
    run(wipFiber)
}
​
function updateFunctionComponent(fiber) {
    effectHooks = []
    stateHooks = []
    stateHookIndex = 0
    wipFiber = fiber
    const children = [fiber.type(fiber.props)]
    reconcileChildren(fiber, children)
}
​
let effectHooks
function useEffect(callback, deps) {
    const effectHook = {
        callback,
        deps
    }
    effectHooks.push(effectHook)
    wipFiber.effectHooks = effectHooks
}
相关推荐
烛阴8 分钟前
WebSocket实时通信入门到实践
前端·javascript
草巾冒小子11 分钟前
vue3实战:.ts文件中的interface定义与抛出、其他文件的调用方式
前端·javascript·vue.js
DoraBigHead36 分钟前
你写前端按钮,他们扛服务器压力:搞懂后端那些“黑话”!
前端·javascript·架构
Xiaouuuuua1 小时前
一个简单的脚本,让pdf开启夜间模式
java·前端·pdf
@Dream_Chaser2 小时前
uniapp ruoyi-app 中使用checkbox 无法选中问题
前端·javascript·uni-app
深耕AI2 小时前
【教程】在ubuntu安装Edge浏览器
前端·edge
倔强青铜三2 小时前
苦练Python第4天:Python变量与数据类型入门
前端·后端·python
倔强青铜三2 小时前
苦练Python第3天:Hello, World! + input()
前端·后端·python
上单带刀不带妹2 小时前
JavaScript中的Request详解:掌握Fetch API与XMLHttpRequest
开发语言·前端·javascript·ecmascript
倔强青铜三2 小时前
苦练Python第2天:安装 Python 与设置环境
前端·后端·python