react hooks原理及实现

简介

本篇文章的内容来源于bilibili Up主《react hooks理念》

hooks的理念:

它是一个被称作为代数效应的思想。代数效应是函数式编程中的一个概念,用于将副作用从函数调用中剥离出去。函数式组件本身是一个函数,那么在函数式编程中有一个理念就叫做代数效应。
为什么要将将副作用从函数调用中剥离出去?我们举个例子。同步 => 异步,如果我们的函数是一个异步的操作,交给IO操作,那么它就是一个有函数副作用的方法。 而在es6中提供了异步的实现方式async aweait,但是它们是具有可传染性的,它的输出结果是一个promise对象。

理解代数效应

我们虚构一种语法perform、 resume with ,然后使用Try catch功能区捕获我们的自定义方法,当我们调用resume with的时候,我们的调用栈就会回到perform id这一行,从而解决不论是否是同步异步所带来的影响

// hooks理念的实现,理解代数效应语法
function getTotalNum(id1, id2) {
  const num1 = getNum(id1); // 1 异步方法请求
  const num2 = getNum(id2); // 2
  return num1 + num2;
}

function getNum(id) {
  const num = perform id;
  return num;
}

// 虚构一种语法
try {
  getTotalNum(1, 2);
} handle(id) {
  switch (id) {
    case 1:
      resume with 230;
    case 2:
      resume with 122;
    default:
      resume with 0;
  }
}
代数效应与Generator

我们知道15版本到16版本,Reat重大的一次重构,主要是在它的协调器上面(Reconciler),主要目的是将:老的同步更新转化为 异步可中断更新。
其实这一转变就是代数效应中try…handle的作用。
Generator: 浏览器原生就支持类似的实现,这就是Generator => async await => promise
如果只考虑“单一优先级任务的中断与继续”情况下Generator可以很好的实现异步可中断更新。
如果通过全局变量保存之前执行的中间状态,又会引入新的复杂度。所以因为这一原因,react团队放弃了 Generator

代数效应与Fiber

React内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态。而我们可以把 Fiber、generator理解为代数效应思想在js中的体现。

react hooks原理及实现_第1张图片

Hooks实现

dispatcher 是包含了hooks函数的共享对象,Hooks queue用顺序下链接在一起的节点。

  1. 它的初始状态在首次渲染时被创建。
  2. 她的状态可以即时更新。
  3. React会在之后的渲染中记住hook的状态
  4. React会根据调用顺序为您提供正确的状态
  5. React会知道这个hook属于哪个Fiber。

react hooks原理及实现_第2张图片

// useState更新实现过程
let isMount = true; // 区分我们的组件是首次调用还是更新调用; componentDidMount updateMount
let workInProgressHook = null // 记录我们hooks指针,当前处理的hooks

const fiber = {
  stateNode: App,  // 这个app组件是在源码的环境中运行的,首先我们每个组件,它在react中都有一个对应的fiber节点。
  memoizedState: null // 保存了函数组件hooks的数据
}

function useState(initialState) {
  let hook;

  if (isMount) {
    hook = {
      memoizedState: initialState || 0,
      next: null,
      queue: {
        pending: null
      }
    }
    if (!fiber.memoizedState) {
      fiber.memoizedState = hook;
      workInProgressHook = hook;
    } else {
      workInProgressHook.next = hook;
    }
  } else {
    hook = workInProgressHook;
    workInProgressHook = workInProgressHook.next;
  }
  
  // 更新状态
  let baseState = hook.memoizedState;

  if (hook.queue.pending) {
    let firstUpdate = hook.queue.pending.next;

    do {
      const action = firstUpdate.action;
      baseState = action(baseState);
      firstUpdate = firstUpdate.next
    } while (firstUpdate !== hook.queue.pending.next)

    hook.queue.pending = null;
  }

  hook.memoizedState = baseState;

  return [baseState, dispatchAction.bind(null, hook.queue)]
}

function dispatchAction(queue, action) {
  const update = { // 环状链表,优先级
    action,
    next: null
  }

  if (queue.pending === null) {
    update.next = update; // u0 -> u0 -> u0
  } else {
    // u0 -> u1 -> u0
    update.next = queue.pending.next;
    queue.pending.next = update;
  }

  queue.pending = update;

  schedule();
}

// 运行执行调度方法
function schedule() {
  workInProgressHook = fiber.memoizedState; // 触发我们的组件
  const app = fiber.stateNode(); // 触发我们的组件
  isMount = false
  return app;
}

// 组件本身
function App() {
  const [num, updateNum] = useState(0); 
  const [count, updateCount] = useState(10);

  console.log('isMount?', isMount)

  console.log('num', num)

  console.log('count:', count)

  return { // 模拟我们的事件点击
    onClick() {
      updateNum(num => num + 1)
    },
    onFocus() {
      updateCount(item => item + 10)
    }
  }
}

window.app = schedule();

你可能感兴趣的:(前端知识,react)