Repository: remix-run/react-router
File: packages/router/router.ts (TypeScript)

Code before:

    // Wire up subscribers to update loaderData as promises settle
    activeDeferreds.forEach((deferredData, routeId) => {
      deferredData.subscribe((aborted) => {
        // Note: No need to updateState here since the TrackedPromise on
        // loaderData is stable across resolve/reject
        // Remove this instance if we were aborted or if promises have settled
        if (aborted || deferredData.done) {
          activeDeferreds.delete(routeId);
        }
      });
    });

    // During partial hydration, preserve SSR errors for routes that don't re-run
    if (future.v7_partialHydration && initialHydration && state.errors) {
      Object.entries(state.errors)
        .filter(([id]) => !matchesToLoad.some((m) => m.route.id === id))
        .forEach(([routeId, error]) => {
          errors = Object.assign(errors || {}, { [routeId]: error });
        });
    }

    let updatedFetchers = markFetchRedirectsDone();
    let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
    let shouldUpdateFetchers =
      updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;

    return {
      matches,
      loaderData,
      errors,
      ...(shouldUpdateFetchers ? { fetchers: new Map(state.fetchers) } : {}),
    };
  }

  function getUpdatedActionData(
    pendingActionResult: PendingActionResult | undefined
  ): Record<string, RouteData> | null | undefined {
    if (pendingActionResult && !isErrorResult(pendingActionResult[1])) {
      // This is cast to `any` currently because `RouteData`uses any and it
      // would be a breaking change to use any.
      // TODO: v7 - change `RouteData` to use `unknown` instead of `any`
      return {
        [pendingActionResult[0]]: pendingActionResult[1].data as any,
      };
    } else if (state.actionData) {
      if (Object.keys(state.actionData).length === 0) {
        return null;
      } else {
        return state.actionData;
      }

Review comment (suggestion):
This didn't work because it would lose errors that had bubbled up - we keep all SSR errors since hydration is not the time to "fix" them, and we let errors thrown from the hydration data load take precedence, but I don't think there will ever be overlap.  Merging is required though so if a higher route throws we catch the error at the higher boundary.

Code after:
        }
      });
    });

    // Preserve SSR errors during partial hydration
    if (future.v7_partialHydration && initialHydration && state.errors) {
      errors = { ...state.errors, ...errors };
    }

    let updatedFetchers = markFetchRedirectsDone();
    let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
    let shouldUpdateFetchers =
      updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;

    return {
      matches,
      loaderData,
      errors,
      ...(shouldUpdateFetchers ? { fetchers: new Map(state.fetchers) } : {}),
    };
  }

  function getUpdatedActionData(
    pendingActionResult: PendingActionResult | undefined
  ): Record<string, RouteData> | null | undefined {
    if (pendingActionResult && !isErrorResult(pendingActionResult[1])) {
      // This is cast to `any` currently because `RouteData`uses any and it
      // would be a breaking change to use any.
      // TODO: v7 - change `RouteData` to use `unknown` instead of `any`
      return {
        [pendingActionResult[0]]: pendingActionResult[1].data as any,
      };
    } else if (state.actionData) {
      if (Object.keys(state.actionData).length === 0) {
        return null;
      } else {
        return state.actionData;
      }
    }
  }

  function getUpdatedRevalidatingFetchers(
    revalidatingFetchers: RevalidatingFetcher[]
  ) {
    revalidatingFetchers.forEach((rf) => {
      let fetcher = state.fetchers.get(rf.key);
      let revalidatingFetcher = getLoadingFetcher(
        undefined,
        fetcher ? fetcher.data : undefined
      );
      state.fetchers.set(rf.key, revalidatingFetcher);