Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[React 19] React Server Components: flushScheduled Initialization in startWork Can Be Improved #32721

Open
KairuiLiu opened this issue Mar 24, 2025 · 0 comments
Labels

Comments

@KairuiLiu
Copy link

Issue Description

Currently in the React Server Components implementation, the startWork function initializes the flushScheduled flag based on whether a destination exists:

export function startWork(request: Request): void {
  request.flushScheduled = request.destination !== null;
  // ...
}

I've analyzed the behavior of this flag across three different scenarios:

  1. When startFlowing is called before startWork (setting destination before beginning rendering) - Effective: Prevents duplicate flush scheduling for the initial render completion.

  2. When startFlowing is called after the initial render completes - No difference: Whether this flag is set or not has no impact on behavior.

  3. When startFlowing is called during the initial render process - Ineffective: The flag cannot correctly control flush behavior in this scenario.

This suggests there's room for improvement in how flush timing is controlled in the current implementation.

Problem

This approach is not robust enough if we want to ensure that no flushing occurs until the initial render is fully complete. The current design relies on indirect state and the timing of API calls, making it brittle and hard to reason about.

The code could be more explicit about its intent to batch initial render output, especially since flushScheduled is primarily used to prevent duplicate flush scheduling rather than controlling flush timing.

Proposed Solution

I propose implementing a more explicit approach to control flushing behavior:

// Add to Request type
type Request = {
  // ...
  flushMode: 'immediate' | 'afterInitialRender',
};

// In startWork
export function startWork(request: Request): void {
  request.initialRenderInProgress = true;
  // ...
}

// After all initial tasks complete in performWork
if (request.pingedTasks.length === 0) {
  request.initialRenderInProgress = false;
  if (request.destination !== null && request.completedRegularChunks.length > 0) {
    flushCompletedChunks(request, request.destination);
  }
}

// Modify enqueueFlush and related functions
function enqueueFlush(request) {
  if (
    !request.initialRenderInProgress &&
    !request.flushScheduled &&
    request.pingedTasks.length === 0 &&
    request.destination !== null
  ) {
    // Schedule flush...
  }
}

This makes the intent clearer and provides more predictable behavior regardless of when startFlowing is called.

Benefits

  1. More explicit control over flushing behavior
  2. Clearer intent in the code
  3. More predictable behavior across different usage patterns

Thank you for considering this improvement

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant