请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

React.useLayoutEffect(create, deps)中create的返回值问题

老师你好。
react官方文档里对useLayoutEffect的介绍:
Parameters:
setup: The function with your Effect’s logic. Your setup function may also optionally return a cleanup function。
但是在视频中的源码,并没有处理React.useLayoutEffect(setup, deps)中setup的返回值问题。
我去看了正版react源码,也没有找到类似于commitPassiveUnmountLayoutEffects(对应于commitPassiveUnmountEffects)的处理逻辑。是不是原版里就没有这个过程呢,还是我没有找到?

正在回答

1回答

// 文件:ReactFiberCommitWork.js
function commitHookEffectListMount(flags, finishedWork) {
    const updateQueue = finishedWork.updateQueue;
    const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
    if (lastEffect !== null) {
        const firstEffect = lastEffect.next;
        let effect = firstEffect;
        do {
            if ((effect.tag & flags) === flags) {
                const create = effect.create;
                effect.destroy = create();
            }
            effect = effect.next;
        } while (effect !== firstEffect)
    }
}

这里

effect.destroy = create();

的destroy,其实就是你提到的setup执行后的返回值,这个destroy具体执行的地方在这里:

// 文件:ReactFiberCommitWork.js
function commitHookEffectListUnmount(flags, finishedWork) {
    const updateQueue = finishedWork.updateQueue;
    const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
    if (lastEffect !== null) {
        const firstEffect = lastEffect.next;
        let effect = firstEffect;
        do {
            if ((effect.tag & flags) === flags) {
                const destroy = effect.destroy;
                if (destroy !== undefined) {
                    destroy();
                }
            }
            effect = effect.next;
        } while (effect !== firstEffect)
    }
}


commitPassiveUnmountEffect函数通过调用链最终调用了commitHookEffectListUnmount处理destroy,你所预期存在的commitPassiveUnmountLayoutEffects,其实没有存在的必要,正如我们视频中所讲到的,无论是effect对象还是layoutEffect对象都在同一个链表中,遍历一次就都处理了。可以认为commitHookEffectListUnmount已经实现了你所推测的commitPassiveUnmountLayoutEffects的逻辑。

可以观察下这张图片上红色框中的effect链表:https://www.yangyitao.com/react18/12Fiber%E6%9E%B6%E6%9E%84-Hooks/01.%E6%9C%AC%E7%AB%A0%E4%BB%8B%E7%BB%8D.html


0 回复 有任何疑惑可以回复我~
  • 提问者 worker1991 #1
    1.老师,commitHookEffectListUnmount可以实现推测的commitPassiveUnmountLayoutEffects的逻辑,但是其传参应该是commitHookEffectListUnmount(HookLayout, finishedWork),否则不会调用effect对象中的destroy属性的值(即函数)的。
    回复 有任何疑惑可以回复我~ 2023-09-25 02:29:19
  • 提问者 worker1991 #2
    2.我又看一遍原版源码,对commitHookEffectListUnmount(HookLayout, finishedWork)的调用是放在commitMutationEffectsOnFiber里的,加上这个处理就对了。
    export function commitMutationEffectsOnFiber(finishedWork, root) {
            ......
            case FunctionComponent:
            case HostRoot:
            case HostText: {
                recursivelyTraverMutationEffects(root, finishedWork);
                commitReconciliationEffects(finishedWork);
            };
            case HostComponent: {
                recursivelyTraverMutationEffects(root, finishedWork);
                commitReconciliationEffects(finishedWork);
                if(flags & Update) {
                    const instance = finishedWork.stateNode;
                    if(instance !== null) {
                        ......
                    }
                    if(flags & LayoutMask) {
                        commitHookEffectListUnmount(HookLayout, finishedWork);
                    }
                }
                break;
            }
        }
    }
    回复 有任何疑惑可以回复我~ 2023-09-25 02:29:45
  • 提问者 worker1991 #3
    3.function commitHookEffectListUnmount(flags, finishedWork) {
        ......
        if(lastEffect !== null) {
            ......
            do {
                if((effect.tag & flags) === flags) {
                    const destroy = effect.destroy;
                    if(destroy !== undefined) {
                        effect.destroy = undefined;
                        destroy();
                    }
                }
                effect = effect.next;
            } while(effect !== firstEffect)
        }
    }
    这里还应该加上effect.destroy = undefined;这个语句,不然destroy会调用两次。(原版里有这个)
    回复 有任何疑惑可以回复我~ 2023-09-25 02:30:00
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信