国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

React16源碼: React中的renderRoot的源碼實(shí)現(xiàn)

這篇具有很好參考價(jià)值的文章主要介紹了React16源碼: React中的renderRoot的源碼實(shí)現(xiàn)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

renderRoot


1 )概述

  • renderRoot 是一個(gè)非常復(fù)雜的方法
  • 這個(gè)方法里處理很多各種各樣的邏輯, 它主要的工作內(nèi)容是什么?
  • A. 它調(diào)用 workLoop 進(jìn)行循環(huán)單元更新
    • 遍歷整個(gè) Fiber Tree,把每一個(gè)組件或者 dom 節(jié)點(diǎn)對(duì)應(yīng)的
    • Fiber 節(jié)點(diǎn)拿出來單一的進(jìn)行更新,這是一個(gè)循環(huán)的操作
    • 把整棵 Fiber Tree 都遍歷一遍,這就是 workLoop
  • B. 捕獲錯(cuò)誤并進(jìn)行處理
    • 在進(jìn)行每一個(gè)單元更新的時(shí)候,這個(gè)遍歷邏輯的時(shí)候,有可能會(huì)出現(xiàn)一些錯(cuò)誤
    • 有些是可預(yù)期的,比如說是 Suspense 的功能, throw 一個(gè) Promise 對(duì)象
    • 這個(gè)時(shí)候,是我們要特殊的對(duì)它進(jìn)行處理的
    • 有一些是不可預(yù)期的,比如說, render 里面報(bào)了一個(gè)錯(cuò)誤
    • 我們也要對(duì)它進(jìn)行一些處理,要告訴我們的react這個(gè)地方
    • 我們出現(xiàn)了一個(gè)錯(cuò)誤,在react16之后,有了 Error Boundary
    • 可以在組件內(nèi)捕獲渲染的錯(cuò)誤
  • C. 在走完流程之后要進(jìn)行善后
    • 因?yàn)榱鞒套咄曛髸?huì)有各種不同的情況
    • 比如說有錯(cuò)誤的情況,比如說有任務(wù)被掛起的情況,也就是Suspense的情況
    • 這些任務(wù),都要按照特定的邏輯給它進(jìn)行一些處理
  • 這就是 renderRoot 這個(gè)方法,它的主要的核心工作內(nèi)容

2 )流程圖

React16源碼: React中的renderRoot的源碼實(shí)現(xiàn),React | React Native,react.js,前端,前端框架
  • 進(jìn)入 renderRoot, 它里面有一個(gè)很核心的循環(huán) do while workLoop
  • 這個(gè)while循環(huán)就是調(diào)用 workLoop 對(duì)整棵樹,它每個(gè)節(jié)點(diǎn)進(jìn)行一個(gè)遍歷,并且拿出來單獨(dú)進(jìn)行更新
  • 因?yàn)槊總€(gè) Fiber節(jié)點(diǎn)上,如果有更新的話,它會(huì)記入 updateQueen
  • 我們通過 updateQueen 上是否有內(nèi)容來判斷它是否要進(jìn)行更新
  • 以及可以計(jì)算出它的新的 state,得到最新的 children,拿到所有最新的節(jié)點(diǎn)
  • 在 workLoop 的過程當(dāng)中,它在做什么呢?
  • nextUnitOfWork 就是每一個(gè)節(jié)點(diǎn)在遍歷的過程當(dāng)中,它自己更新完之后,它會(huì)返回它的第一個(gè)child
  • 它的第一個(gè)child 就是作為 nextUnitOfWork,因?yàn)槲覀儓?zhí)行了一個(gè)節(jié)點(diǎn)的更新之后,我們需要返回
  • 返回之后,我們要判斷一些邏輯
  • 比如,對(duì)于異步的操作,每個(gè)節(jié)點(diǎn)更新完之后都要判斷 !shouldYield()
  • 判斷我們現(xiàn)在的時(shí)間片是否還有?如果還有的話,再繼續(xù),如果沒有的話,就要跳出了
  • 接下去就會(huì)執(zhí)行 performUnitOfWork
  • 之后,執(zhí)行 beginWork, completeUnitOfWork 這些,當(dāng)然中間會(huì)判斷是否有 next
  • next就是我在更新完一個(gè)結(jié)點(diǎn)之后,它是否還有下一個(gè)節(jié)點(diǎn)需要更新
  • 如果有next的情況,我們就返回,然后去判斷這個(gè)邏輯是否還有
  • 這就是整個(gè)對(duì)整個(gè) fiber tree 每個(gè)節(jié)點(diǎn)的遍歷更新
  • 在這個(gè)更新過程當(dāng)中,如果有任何catch,就是捕獲到異常
  • 那么首先會(huì)進(jìn)行一系列的判斷,然后對(duì)它執(zhí)行 throwException 或者是 onUncaughtError
  • 它們對(duì)應(yīng)的邏輯會(huì)不一樣, 如果這個(gè)節(jié)點(diǎn)它是可處理的錯(cuò)誤
  • 我會(huì)直接對(duì)它進(jìn)行 completeUnitOfWork() 因?yàn)楦碌竭@個(gè)節(jié)點(diǎn)之后,它拋出錯(cuò)誤了
  • 說明我們這個(gè)節(jié)點(diǎn)下面的所有子節(jié)點(diǎn)都不需要再更新了
  • 執(zhí)行完成之后,我們就會(huì)調(diào)用 continue,對(duì)于這個(gè) do while 循環(huán),它又繼續(xù)調(diào)用 workLoop
  • 也就是說我們把一棵子數(shù)的錯(cuò)誤處理完之后,它還可以繼續(xù)對(duì)別的子樹進(jìn)行更新
  • 整體更新完之后,就會(huì) break,之后會(huì)有各種不同的情況,比如說有致命的錯(cuò)誤等
  • 它們都會(huì)調(diào)用不同的邏輯進(jìn)行一個(gè)處理,這里 nextRenderDidError 是一個(gè)可處理的錯(cuò)誤
  • 比如說, 是可以被捕獲的錯(cuò)誤,有組件能捕獲它,而 nextLatestAbsoluteTimeoutMs 是拋出promise的錯(cuò)誤
  • 它是一個(gè)被掛起的一個(gè)任務(wù),對(duì)應(yīng)要執(zhí)行一個(gè)被被掛起的操作, 最后如果上面的情況都沒有出現(xiàn)
  • 直接 onComplete,之后就可以在root節(jié)點(diǎn)上 set finishedwork,這樣, 就可以對(duì)它整體進(jìn)行一個(gè)更新
  • 就可以執(zhí)行 completeRoot,就可以把 fiber樹 變成我們真正的dom 樹去更新整個(gè)頁面
  • 這就是整個(gè) renderRoot 它的一個(gè)邏輯,簡單總結(jié)
    • 先正常的執(zhí)行每個(gè)單元的更新
    • 然后捕獲到任何錯(cuò)誤進(jìn)行一定的處理
    • 最終把整個(gè)樹遍歷完之后根據(jù)不同的情況再進(jìn)行一個(gè)處理

3 )源碼

定位到 packages/react-reconciler/src/ReactFiberScheduler.js

先看 renderRoot 的代碼

function renderRoot(
  root: FiberRoot,
  isYieldy: boolean,
  isExpired: boolean,
): void {
  invariant(
    !isWorking,
    'renderRoot was called recursively. This error is likely caused ' +
      'by a bug in React. Please file an issue.',
  );
  isWorking = true;
  ReactCurrentOwner.currentDispatcher = Dispatcher;

  const expirationTime = root.nextExpirationTimeToWorkOn;

  // Check if we're starting from a fresh stack, or if we're resuming from
  // previously yielded work.
  // 剛進(jìn)來的時(shí)候,進(jìn)行這個(gè)判斷
  // nextRoot 和 nextRenderExpirationTime 對(duì)應(yīng)著接下來要渲染的節(jié)點(diǎn)和對(duì)應(yīng)的過期時(shí)間 這是兩個(gè)公共變量
  // 在這種情況下,說明調(diào)用這個(gè)方法的時(shí)候,接收到的參數(shù)和之前的不一樣,可能就是之前的異步任務(wù)被新進(jìn)來的高優(yōu)先級(jí)的任務(wù)給打斷了
  if (
    expirationTime !== nextRenderExpirationTime ||
    root !== nextRoot ||
    nextUnitOfWork === null
  ) {
    // Reset the stack and start working from the root.
    resetStack();
    nextRoot = root;
    nextRenderExpirationTime = expirationTime;
    // nextUnitOfWork 來自于 createWorkInProgress
    // 就是把當(dāng)前的應(yīng)用的狀態(tài)對(duì)應(yīng)的Fiber節(jié)點(diǎn),拷貝了一份叫做 workInProgress 的對(duì)象
    // 因?yàn)槲覀儾荒苤苯釉诋?dāng)前對(duì)象的Fiber節(jié)點(diǎn)上操作,它會(huì)影響我們目前的dom節(jié)點(diǎn)展示的樣子
    // 所以要復(fù)制一份拷貝,對(duì)拷貝進(jìn)行操作,workInProgress 和 current 之間會(huì)有一個(gè)轉(zhuǎn)換的關(guān)系
    // 在renderRoot開始之后,我們真正操作的節(jié)點(diǎn)都是 workInProgress,沒有直接在 current 上操作
    nextUnitOfWork = createWorkInProgress(
      nextRoot.current,
      null,
      nextRenderExpirationTime,
    );
    // 這種和不同expirationTime會(huì)有關(guān)系
    root.pendingCommitExpirationTime = NoWork;

    if (enableSchedulerTracing) {
      // Determine which interactions this batch of work currently includes,
      // So that we can accurately attribute time spent working on it,
      // And so that cascading work triggered during the render phase will be associated with it.
      const interactions: Set<Interaction> = new Set();
      root.pendingInteractionMap.forEach(
        (scheduledInteractions, scheduledExpirationTime) => {
          if (scheduledExpirationTime <= expirationTime) {
            scheduledInteractions.forEach(interaction =>
              interactions.add(interaction),
            );
          }
        },
      );

      // Store the current set of interactions on the FiberRoot for a few reasons:
      // We can re-use it in hot functions like renderRoot() without having to recalculate it.
      // We will also use it in commitWork() to pass to any Profiler onRender() hooks.
      // This also provides DevTools with a way to access it when the onCommitRoot() hook is called.
      root.memoizedInteractions = interactions;

      if (interactions.size > 0) {
        const subscriber = __subscriberRef.current;
        if (subscriber !== null) {
          const threadID = computeThreadID(
            expirationTime,
            root.interactionThreadID,
          );
          try {
            subscriber.onWorkStarted(interactions, threadID);
          } catch (error) {
            // Work thrown by an interaction tracing subscriber should be rethrown,
            // But only once it's safe (to avoid leaveing the scheduler in an invalid state).
            // Store the error for now and we'll re-throw in finishRendering().
            if (!hasUnhandledError) {
              hasUnhandledError = true;
              unhandledError = error;
            }
          }
        }
      }
    }
  }

  let prevInteractions: Set<Interaction> = (null: any);
  if (enableSchedulerTracing) {
    // We're about to start new traced work.
    // Restore pending interactions so cascading work triggered during the render phase will be accounted for.
    prevInteractions = __interactionsRef.current;
    __interactionsRef.current = root.memoizedInteractions;
  }

  let didFatal = false;

  startWorkLoopTimer(nextUnitOfWork);

  // 上面初始化工作做完之后,就開始 workLoop
  // 如果有 catch 就會(huì)有一大段處理邏輯, 這里先跳過
  // 
  do {
    try {
      workLoop(isYieldy);
    } catch (thrownValue) {
      if (nextUnitOfWork === null) {
        // This is a fatal error.
        didFatal = true;
        onUncaughtError(thrownValue);
      } else {
        if (__DEV__) {
          // Reset global debug state
          // We assume this is defined in DEV
          (resetCurrentlyProcessingQueue: any)();
        }

        const failedUnitOfWork: Fiber = nextUnitOfWork;
        if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
          replayUnitOfWork(failedUnitOfWork, thrownValue, isYieldy);
        }

        // TODO: we already know this isn't true in some cases.
        // At least this shows a nicer error message until we figure out the cause.
        // https://github.com/facebook/react/issues/12449#issuecomment-386727431
        invariant(
          nextUnitOfWork !== null,
          'Failed to replay rendering after an error. This ' +
            'is likely caused by a bug in React. Please file an issue ' +
            'with a reproducing case to help us find it.',
        );

        const sourceFiber: Fiber = nextUnitOfWork;
        let returnFiber = sourceFiber.return;
        if (returnFiber === null) {
          // This is the root. The root could capture its own errors. However,
          // we don't know if it errors before or after we pushed the host
          // context. This information is needed to avoid a stack mismatch.
          // Because we're not sure, treat this as a fatal error. We could track
          // which phase it fails in, but doesn't seem worth it. At least
          // for now.
          didFatal = true;
          onUncaughtError(thrownValue);
        } else {
          throwException(
            root,
            returnFiber,
            sourceFiber,
            thrownValue,
            nextRenderExpirationTime,
          );
          nextUnitOfWork = completeUnitOfWork(sourceFiber);
          continue;
        }
      }
    }
    break;
  } while (true);

  if (enableSchedulerTracing) {
    // Traced work is done for now; restore the previous interactions.
    __interactionsRef.current = prevInteractions;
  }

  // We're done performing work. Time to clean up.
  isWorking = false;
  ReactCurrentOwner.currentDispatcher = null;
  resetContextDependences();

  // 在處理完 workLoop 后這里會(huì)有各種不同的判斷
  // Yield back to main thread.
  // 這里代表有致命的錯(cuò)誤
  if (didFatal) {
    const didCompleteRoot = false;
    stopWorkLoopTimer(interruptedBy, didCompleteRoot);
    interruptedBy = null;
    // There was a fatal error.
    if (__DEV__) {
      resetStackAfterFatalErrorInDev();
    }
    // `nextRoot` points to the in-progress root. A non-null value indicates
    // that we're in the middle of an async render. Set it to null to indicate
    // there's no more work to be done in the current batch.
    nextRoot = null;
    onFatal(root);
    return;
  }

  // 正常流程走完,這個(gè)if一定會(huì)匹配
  // 因?yàn)橐呀?jīng)跳出 workLoop 了,說明一定有 react沒有意識(shí)到的錯(cuò)誤,所以調(diào)用 onYield
  if (nextUnitOfWork !== null) {
    // There's still remaining async work in this tree, but we ran out of time
    // in the current frame. Yield back to the renderer. Unless we're
    // interrupted by a higher priority update, we'll continue later from where
    // we left off.
    const didCompleteRoot = false;
    stopWorkLoopTimer(interruptedBy, didCompleteRoot);
    interruptedBy = null;
    onYield(root);
    return;
  }

  // We completed the whole tree.
  const didCompleteRoot = true;
  stopWorkLoopTimer(interruptedBy, didCompleteRoot);
  const rootWorkInProgress = root.current.alternate;
  invariant(
    rootWorkInProgress !== null,
    'Finished root should have a work-in-progress. This error is likely ' +
      'caused by a bug in React. Please file an issue.',
  );

  // `nextRoot` points to the in-progress root. A non-null value indicates
  // that we're in the middle of an async render. Set it to null to indicate
  // there's no more work to be done in the current batch.
  nextRoot = null;
  interruptedBy = null;

  // 這里也是
  if (nextRenderDidError) {
    // There was an error
    if (hasLowerPriorityWork(root, expirationTime)) {
      // There's lower priority work. If so, it may have the effect of fixing
      // the exception that was just thrown. Exit without committing. This is
      // similar to a suspend, but without a timeout because we're not waiting
      // for a promise to resolve. React will restart at the lower
      // priority level.
      markSuspendedPriorityLevel(root, expirationTime);
      const suspendedExpirationTime = expirationTime;
      const rootExpirationTime = root.expirationTime;
      onSuspend(
        root,
        rootWorkInProgress,
        suspendedExpirationTime,
        rootExpirationTime,
        -1, // Indicates no timeout
      );
      return;
    } else if (
      // There's no lower priority work, but we're rendering asynchronously.
      // Synchronsouly attempt to render the same level one more time. This is
      // similar to a suspend, but without a timeout because we're not waiting
      // for a promise to resolve.
      !root.didError &&
      !isExpired
    ) {
      root.didError = true;
      const suspendedExpirationTime = (root.nextExpirationTimeToWorkOn = expirationTime);
      const rootExpirationTime = (root.expirationTime = Sync);
      onSuspend(
        root,
        rootWorkInProgress,
        suspendedExpirationTime,
        rootExpirationTime,
        -1, // Indicates no timeout
      );
      return;
    }
  }

  // 注意這里的錯(cuò)誤
  if (!isExpired && nextLatestAbsoluteTimeoutMs !== -1) {
    // The tree was suspended.
    const suspendedExpirationTime = expirationTime;
    markSuspendedPriorityLevel(root, suspendedExpirationTime);

    // Find the earliest uncommitted expiration time in the tree, including
    // work that is suspended. The timeout threshold cannot be longer than
    // the overall expiration.
    const earliestExpirationTime = findEarliestOutstandingPriorityLevel(
      root,
      expirationTime,
    );
    const earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime);
    if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) {
      nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs;
    }

    // Subtract the current time from the absolute timeout to get the number
    // of milliseconds until the timeout. In other words, convert an absolute
    // timestamp to a relative time. This is the value that is passed
    // to `setTimeout`.
    const currentTimeMs = expirationTimeToMs(requestCurrentTime());
    let msUntilTimeout = nextLatestAbsoluteTimeoutMs - currentTimeMs;
    msUntilTimeout = msUntilTimeout < 0 ? 0 : msUntilTimeout;

    // TODO: Account for the Just Noticeable Difference

    const rootExpirationTime = root.expirationTime;
    onSuspend(
      root,
      rootWorkInProgress,
      suspendedExpirationTime,
      rootExpirationTime,
      msUntilTimeout,
    );
    return;
  }

  // Ready to commit.
  onComplete(root, rootWorkInProgress, expirationTime);
}
  • renderRoot 代碼會(huì)相對(duì)比較長,要把代碼的區(qū)塊進(jìn)行一個(gè)區(qū)分
  • 一些原版英文注釋,和我添加的中文注釋如上

現(xiàn)在來看下 workLoop 的源碼

function workLoop(isYieldy) {
  if (!isYieldy) {
    // Flush work without yielding
    while (nextUnitOfWork !== null) {
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  } else {
    // Flush asynchronous work until the deadline runs out of time.
    while (nextUnitOfWork !== null && !shouldYield()) {
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  }
}
  • 它接收一個(gè) isYieldy 作為參數(shù)
  • 這個(gè)參數(shù)意味著是否可以被中斷
  • Sync的任務(wù)和已超時(shí)的異步任務(wù)都是不可中斷的
  • 如果是不可中斷的,只要有 nextUnitOfWork
  • 就會(huì)繼續(xù)調(diào)用 performUnitOfWork
  • 如果是可以中斷的,就通過判斷 !shouldYield()
  • 來看當(dāng)前時(shí)間片中是否還有足夠的時(shí)間繼續(xù)渲染下一個(gè)節(jié)點(diǎn)

再來看下 performUnitOfWork文章來源地址http://www.zghlxwxcb.cn/news/detail-797722.html

function performUnitOfWork(workInProgress: Fiber): Fiber | null {
  // The current, flushed, state of this fiber is the alternate.
  // Ideally nothing should rely on this, but relying on it here
  // means that we don't need an additional field on the work in
  // progress.
  const current = workInProgress.alternate;

  // See if beginning this work spawns more work.
  startWorkTimer(workInProgress);
  if (__DEV__) {
    ReactCurrentFiber.setCurrentFiber(workInProgress);
  }

  if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
    stashedWorkInProgressProperties = assignFiberPropertiesInDEV(
      stashedWorkInProgressProperties,
      workInProgress,
    );
  }

  let next;
  if (enableProfilerTimer) {
    if (workInProgress.mode & ProfileMode) {
      startProfilerTimer(workInProgress);
    }

    next = beginWork(current, workInProgress, nextRenderExpirationTime);
    workInProgress.memoizedProps = workInProgress.pendingProps;

    if (workInProgress.mode & ProfileMode) {
      // Record the render duration assuming we didn't bailout (or error).
      stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true);
    }
  } else {
    next = beginWork(current, workInProgress, nextRenderExpirationTime);
    workInProgress.memoizedProps = workInProgress.pendingProps;
  }

  if (__DEV__) {
    ReactCurrentFiber.resetCurrentFiber();
    if (isReplayingFailedUnitOfWork) {
      // Currently replaying a failed unit of work. This should be unreachable,
      // because the render phase is meant to be idempotent, and it should
      // have thrown again. Since it didn't, rethrow the original error, so
      // React's internal stack is not misaligned.
      rethrowOriginalError();
    }
  }
  if (__DEV__ && ReactFiberInstrumentation.debugTool) {
    ReactFiberInstrumentation.debugTool.onBeginWork(workInProgress);
  }

  if (next === null) {
    // If this doesn't spawn new work, complete the current work.
    next = completeUnitOfWork(workInProgress);
  }

  ReactCurrentOwner.current = null;

  return next;
}
  • 它聲明了一個(gè) next 變量,next = beginWork(…), 這里涉及到對(duì)每個(gè)節(jié)點(diǎn)的更新
    • 更新完一個(gè)節(jié)點(diǎn)之后,它會(huì)返回它的下一個(gè)節(jié)點(diǎn)
    • 會(huì)更新 workInProgress.memoizedProps, 節(jié)點(diǎn)已經(jīng)更新完了
    • 最新的 props 已經(jīng)變成目前正在用的 props
    • 先跳過
  • 跳過 DEV 的代碼
  • 如果 next === null 說明這個(gè)節(jié)點(diǎn)已經(jīng)更新到子樹的葉子節(jié)點(diǎn)了
    • 這棵子樹就可以結(jié)束了
    • 結(jié)束就調(diào)用 completeUnitOfWork
    • 它也會(huì)返回它的下一個(gè)節(jié)點(diǎn)
  • 最后,return next
    • 在 workLoop 函數(shù)中可看到,它會(huì)賦值給 nextUnitOfWork
      // 參考其中一個(gè) while
      while (nextUnitOfWork !== null) {
        nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
      }
      
    • 所以,真正到 nextUnitOfWork 為 null 的情況是它到了根節(jié)點(diǎn),即 FiberRoot 節(jié)點(diǎn)
    • 它的 return 是 null,這時(shí)就跳出了 while 循環(huán)了

到了這里,關(guān)于React16源碼: React中的renderRoot的源碼實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • React16源碼: React中的beginWork的源碼實(shí)現(xiàn)

    beginWork 1 )概述 在 renderRoot 之后,要對(duì)我們的 Fiber 樹每一個(gè)節(jié)點(diǎn)進(jìn)行對(duì)應(yīng)的更新 更新節(jié)點(diǎn)的一個(gè)入口方法,就是 beginWork 這個(gè)入口方法會(huì)有幫助我們?nèi)?yōu)化整棵樹的更新過程 react 它的節(jié)點(diǎn)其實(shí)是非常多的,如果每一次子節(jié)點(diǎn)的一個(gè)更新 就需要每一個(gè)節(jié)點(diǎn)都執(zhí)行一遍更新的話

    2024年01月20日
    瀏覽(24)
  • React16源碼: React中的updateHostRoot的源碼實(shí)現(xiàn)

    HostRoot 的更新 1 )概述 HostRoot 是一個(gè)比較特殊的節(jié)點(diǎn), 因?yàn)樵谝粋€(gè)react應(yīng)用當(dāng)中 它只會(huì)有一個(gè) HostRoot , 它對(duì)應(yīng)的 Fiber 對(duì)象是我們的 RootFiber 對(duì)象 重點(diǎn)在于它的更新過程 2 )源碼 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js#L612 HostRoot 創(chuàng)建更新的過程就是在 ReactFiberReconcile

    2024年01月22日
    瀏覽(29)
  • React16源碼: React中的IndeterminateComponent的源碼實(shí)現(xiàn)

    IndeterminateComponent 1 )概述 這是一個(gè)比較特殊的component的類型, 就是還沒有被指定類型的component 在一個(gè)fibrer被創(chuàng)建的時(shí)候,它的tag可能會(huì)是 IndeterminateComponent 在 packages/react-reconciler/src/ReactFiber.js 中,有一個(gè)方法 createFiberFromTypeAndProps 中,一開始就聲明了 在最終調(diào)用 createFibe

    2024年01月21日
    瀏覽(20)
  • React16源碼: React中的completeUnitOfWork的源碼實(shí)現(xiàn)

    React16源碼: React中的completeUnitOfWork的源碼實(shí)現(xiàn)

    completeUnitOfWork 1 )概述 各種不同類型組件的一個(gè)更新過程對(duì)應(yīng)的是在執(zhí)行 performUnitOfWork 里面的 beginWork 階段 它是去向下遍歷一棵 fiber 樹的一側(cè)的子節(jié)點(diǎn),然后遍歷到葉子節(jié)點(diǎn)為止,以及 return 自己 child 的這種方式 在 performUnitOfWork 里面,還有一個(gè)方法叫做 completeUnitOfWork 在

    2024年01月23日
    瀏覽(33)
  • React16源碼: React中的setState和forceUpdate源碼實(shí)現(xiàn)

    setState 和 forceUpdate 1 ) 概述 通過 class component 內(nèi)部的 setState ,以及 forceUpdate 去更新一個(gè)組件的過程 在react的應(yīng)用當(dāng)中,我們只有 ReactDOM.render setState ,以及 forceUpdate 這幾種種方式去更新react的應(yīng)用是合理的,其他沒有什么特別常用的方式去更新了 而且react官方推薦的也是用

    2024年01月25日
    瀏覽(22)
  • React16源碼: React中的HostComponent & HostText的源碼實(shí)現(xiàn)

    HostComponent HostText 1 )概述 HostComponent 就是我們dom原生的這些節(jié)點(diǎn), 如: div, span, p 標(biāo)簽這種 使用的是小寫字母開頭的這些節(jié)點(diǎn)一般都認(rèn)為它是一個(gè) HostComponent HostText ,它是單純的文本節(jié)點(diǎn) 主要關(guān)注它們的一個(gè)更新過程 2 )源碼 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js 進(jìn)

    2024年01月24日
    瀏覽(19)
  • React16源碼: React中的reconcileChildIterator和reconcileChildrenArray的源碼實(shí)現(xiàn)

    reconcileChildIterator 和 reconcileChildrenArray 1 )概述 在react更新某一個(gè)節(jié)點(diǎn)的時(shí)候,要根據(jù)這個(gè)節(jié)點(diǎn),它的類型去獲取它的children 比如說如果是 Function Component,它要調(diào)用這個(gè) component 計(jì)算出它的return的屬性 return的屬性可能是一個(gè)數(shù)組,可能是單個(gè)的 ReactElement,可能是 number, string

    2024年01月20日
    瀏覽(46)
  • React16源碼: React中的不同的expirationTime的源碼實(shí)現(xiàn)

    不同的 expirationTime 1 )概述 在React中不僅僅有異步任務(wù) 大部分情況下都是同步的任務(wù),所以會(huì)有不同 expirationTime 的存在 2 )種類 A. Sync 模式,優(yōu)先級(jí)最高 任務(wù)創(chuàng)建完成之后,立馬更新到真正的dom里面 是一個(gè)創(chuàng)建即更新的流程 B. Async 模式, 異步模式 會(huì)有一個(gè)調(diào)度 包含一系列

    2024年02月01日
    瀏覽(19)
  • React16源碼: React中的PortalComponent創(chuàng)建, 調(diào)和, 更新的源碼實(shí)現(xiàn)

    PortalComponent 1 )概述 React Portal之所以叫Portal,因?yàn)樽龅木褪呛汀皞魉烷T”一樣的事情 render到一個(gè)組件里面去,實(shí)際改變的是網(wǎng)頁上另一處的DOM結(jié)構(gòu) 主要關(guān)注 portal的創(chuàng)建, 調(diào)和, 更新過程 2 )源碼 定位到 packages/react-dom/src/client/ReactDOM.js#L576 這里調(diào)用的是 ReactPortal.createPortal ,

    2024年01月21日
    瀏覽(25)
  • React16源碼: React中的update和updateQueue的源碼實(shí)現(xiàn)

    React中的update和updateQueue 1 )概述 在 ReactDOM.render 過程中,還需要?jiǎng)?chuàng)建一個(gè) update 對(duì)象 update 用于記錄組件狀態(tài)的改變的一個(gè)對(duì)象,它存放于Fiber對(duì)象的 updateQueue 中 updateQueue ,它是一個(gè)單向鏈表的結(jié)構(gòu),一次整體的更新過程當(dāng)中 可能在這個(gè)queue里會(huì)存在多 Update 在這次更新的過

    2024年02月02日
    瀏覽(14)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包