手写实现useState,useEffect,useReduce,useMemo,useCallback

155 阅读2分钟

useState

memorizeState中保存的是state的值,传入相同的值不会进行更新

import React from 'react';
import App from '../../App';
import root from '../..';   // ReactDOM.createRoot(document.getElementById('root'));

function render() {
  // 每次重新渲染就初始化hooks链表的指针
  hooksIndex = 0
  effectIndex = 0
  memoIndex = 0
  callbIndex = 0
  // 获取 React 节点
  root.render(<App />)
}

// useState的hooks对象上保存state
const states = []
// hooks数组的index(类似于hooks链表,用于标识当前hook是第几个hook对象)
let hooksIndex = 0

function useState(initialState) {
  // 初次渲染取初始值,不然就取hook对象上保存的state
  states[hooksIndex] = states[hooksIndex] ? states[hooksIndex] : initialState

  function createStateSetter(hooksIndex) {
    return (newState) => {
      // 区分函数和纯数值情况,更新state
      if (typeof newState === 'function') {
        states[hooksIndex] = newState(states[hooksIndex])
      } else {
        states[hooksIndex] = newState
      }
      render() // 重新渲染视图
    }
  }

  const _state = states[hooksIndex]
  const _setSetter = createStateSetter(hooksIndex)
  hooksIndex++

  return [_state, _setSetter]
}

useReduce

function useReduce(reduce,initValue){
  const [state, setState] = useState(initValue)
  const dispatch = (action) => {
    setState(reduce(state,action))
  }
  return [state,dispatch]
}

useEffect:

// effctIndex, 销毁函数数组,依赖项数组
let effectIndex = 0
let curIndex = effectIndex++
let destory = []
let depArr = []
function useEffect(callback, deps) {
  // 判断是否为初次渲染,deps为空,或者依赖项改变
  let preDep = depArr[curIndex]
  let change = !preDep || !deps || deps.some((dep, index) => dep !== preDep[index])
  if (change) {
    // 执行上次的销毁函数,执行callback,更新deps,销毁函数数组
    if (destory[curIndex]) {
      destory[curIndex]()
    }
    destory[curIndex] = callback()
    depArr[curIndex] = deps
  }
}

memo

import React, { Component, PureComponent } from 'react'

export default class PureComponentPage extends PureComponent {
    constructor(props) {
        super(props);
        this.state = { count: 0 }
    }

    setCount = () => {
        this.setState({ count: 10 })
    }

    render() {
        console.log("render");
        const { count } = this.state
        return (
            <div>
                <button onClick={this.setCount}>{count}</button>
            </div>
        )
    }
}
export function memo(FC) {
  // 匿名类的定义,它继承自 PureComponent,并覆盖了 render 方法。
  return class extends PureComponent {
    render() {
      // 调用原始的函数组件 FC,并将 props 传递给它
      return FC(this.props)
    }
  }
}

useMemo

依赖改变,则返回重新计算的值

// memoIndex,依赖数组,缓存的计算结果
let memoIndex = 0
let memoDeps = []
let memoState = []
function useMemo(callback, deps) {
  // 检查依赖项是否改变
  let preDep = memoDeps[memoIndex]
  let change = !preDep || !deps || deps.some((dep, index) => dep !== preDep[index])
  // 依赖改变,重新执行callBack,计算新的结果,保存到memoState,更新依赖数组
  if (change) {
    let curMemo = callback()
    memoState[memoIndex] = curMemo
    memoDeps[memoIndex] = deps
    memoIndex++
    return curMemo
  }
  // 依赖没有改变,返回上次缓存的计算结果
  let memo = memoState[memoIndex]
  memoIndex++
  return memo
}

useCallback

// callbIndex,依赖数组,缓存的callback地址
let callbIndex = 0
let callbDeps = []
let callbState = []
function useCallback(callback, deps) {
  // 检查依赖项是否改变
  let preDep = callbDeps[callbIndex]
  let change = !preDep || !deps || deps.some((dep, index) => dep !== preDep[index])
  // 依赖改变,更新依赖数组,更新缓存的callback地址
  if (change) {
    callbState[callbIndex] = callback
    callbDeps[callbIndex] = deps
    callbIndex++
    return callback
  }
  // 依赖没有改变,返回上次缓存的callback
  let callb = callbState[callbIndex]
  callbIndex++
  return callb
}

参考文章:www.xcj.com/front-end-l…