react hooks 源码学习记录

根据react的使用自己实现一个hooks

react源码中的实现

react hooks中的数据结构
export type Hook = {|
  memoizedState: any, // 当前state的值
  baseState: any,
  baseQueue: Update<any, any> | null,
  queue: UpdateQueue<any, any> | null, // 更新队列
  next: Hook | null, // 指针指向下一个hook对象
|};

export type Effect = {|
  tag: HookFlags, // 当前effct的类型,触发的阶段
  create: () => (() => void) | void, // useEffect回调
  destroy: (() => void) | void, // useEffect回调的返回函数
  deps: Array<mixed> | null, // 依赖
  next: Effect, // 指针指向下一个effect
|};

type UpdateQueue<S, A> = {|
  pending: Update<S, A> | null, //记录的是update的链表
  dispatch: (A => mixed) | null,
  lastRenderedReducer: ((S, A) => S) | null,
  lastRenderedState: S | null,
|};
Dispatcher来源

根据renderWithHooksfiber, currentFiber,当前环境进行区分;
讲一下mountHookTypesDev, updateHooks

// src/react/packages/react-reconciler/src/ReactFiberHooks.old.js
export function renderWithHooks<Props, SecondArg>(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: (p: Props, arg: SecondArg) => any,
  props: Props,
  secondArg: SecondArg,
  nextRenderLanes: Lanes,
): any {
	renderLanes = nextRenderLanes;
  	currentlyRenderingFiber = workInProgress;
  	if(__DEV__) {
  	...
  	}
  	else {
  	    ReactCurrentDispatcher.current =
      current === null || current.memoizedState === null
        ? HooksDispatcherOnMount
        : HooksDispatcherOnUpdate;}

理解bind(null, …args)
默认使用下一个函数的传参作为参数;
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
传入的reducer,baseState,是用来在update时候进行优化的;

useEffect相关问题

问题一:
为什么在dep没有改变的情况下,不走useEffect的回调,原理是什么?
看一个简单的例子:

import * as React from "react";
import * as ReactDOM from "react-dom";

import {Component, useState, useEffect} from "react";

export default class ClassFunctionComponent extends Component {
  render() {
    return (
      <div>
        <h3>ClassFunctionComponent</h3>
        <FunctionComponent />
      </div>
    );
  }
}
function FunctionComponent(props) {
  const [count, setCount] = useState(0);
  const [val, setVal] = useState("");

  const add = () => {
    setCount(count + 1);
  };
  useEffect(() => {
    debugger
    console.log("useEffect", count); //sy-log
  }, [count]);

  const handleChange = e => {
    setVal(data => e.target.value);
  };
  return (
    <div className="border">
      <h3>FunctionComponent</h3>
      <p>{count}</p>
      <button onClick={add}>add</button>
      <input type="text" value={val} onChange={handleChange} />
    </div>
  );
}

useEffect在源码中调用的是
src/react/packages/react-reconciler/src/ReactFiberHooks.old.js

function mountEffectImpl(fiberFlags, hookFlags, create, deps): void {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  currentlyRenderingFiber.flags |= fiberFlags;
  hook.memoizedState = pushEffect(
    HookHasEffect | hookFlags,
    create,
    undefined,
    nextDeps,
  );
}

function updateEffectImpl(fiberFlags, hookFlags, create, deps): void {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  let destroy = undefined;

  if (currentHook !== null) {
    const prevEffect = currentHook.memoizedState;
    destroy = prevEffect.destroy;
    if (nextDeps !== null) {
      const prevDeps = prevEffect.deps;
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        pushEffect(hookFlags, create, destroy, nextDeps);
        return;
      }
    }
  }
  currentlyRenderingFiber.flags |= fiberFlags;
  hook.memoizedState = pushEffect(
    HookHasEffect | hookFlags,
    create,
    destroy,
    nextDeps,
  );
}

对于依赖没有改变的情况,不需要挂到hook.memoizedState上,只是执行了pushEffect,只有在依赖变化时候,pushEffect的参数才会带上hookHasEffect去执行后续

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值