Skip to content

Comments

Re-implement Server Action reducer (#86367)#9

Open
MitchLewis930 wants to merge 1 commit intopr_039_beforefrom
pr_039_after
Open

Re-implement Server Action reducer (#86367)#9
MitchLewis930 wants to merge 1 commit intopr_039_beforefrom
pr_039_after

Conversation

@MitchLewis930
Copy link

PR_039

Rewrite of the Server Action reducer to use the PPR/Segment Cache
navigation implementation, rather than the old lazy fetch
implementation.

Server Actions may trigger a revalidation, a redirect, or both. They may
also invalidate the cache. The behavior could be naively implemented
using router.refresh() and router.push(). Semantically, the routing
behavior is equivalent.

The main difference is that the server that invokes the action may also
send back new data for the page within the same response. Compared to a
separate request, this data is more likely to be consistent with any
data that may have been mutated by the action, due to global data
propagation races. (It's also faster since it avoids an extra server
waterfall.)

So, navigations initiated by a Server action must be able to "seed" the
navigation with the data it just received from the server. I've added a
new internal method, navigateToSeededRoute, that implements this
behavior.
@greptile-apps
Copy link

greptile-apps bot commented Jan 30, 2026

Greptile Overview

Greptile Summary

This PR re-implements the server action reducer to use a unified navigation approach. The main changes include:

  • Server action navigation unification: Replaced custom navigation logic in server-action-reducer.ts with calls to navigateToSeededRoute and navigateUsingSegmentCache, making server actions use the same navigation flow as regular navigations
  • Seed data propagation: Added seedData and seedHead parameters throughout the navigation tree (in ppr-navigations.ts) to support "seeded" navigations where the server sends back route data as part of the action response
  • Refresh refactoring: The refresh function in segment-cache/navigation.ts was removed and replaced with navigateToSeededRoute, modeling refresh as a navigation with shouldRefreshDynamicData=true
  • Enhanced response payloads: Server responses now include q (renderedSearch) and i (couldBeIntercepted) fields to provide additional context needed for proper navigation handling

The implementation prioritizes using data from server action responses over separate requests for better performance and consistency with mutations just performed by the action.

Confidence Score: 4/5

  • Safe to merge with low risk - well-structured refactoring with consistent patterns
  • The refactoring consolidates navigation logic into a unified approach, reducing code duplication and improving maintainability. The changes follow existing patterns and include proper type definitions. However, this touches critical router infrastructure with complex asynchronous flows, so thorough testing is recommended.
  • packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts requires the most attention due to significant logic changes

Important Files Changed

Filename Overview
packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts Re-implemented server action reducer to use navigateToSeededRoute and navigateUsingSegmentCache for more consistent navigation handling
packages/next/src/client/components/router-reducer/ppr-navigations.ts Added seedData and seedHead parameters throughout navigation tree to support seeded route navigation from server actions
packages/next/src/client/components/segment-cache/navigation.ts Refactored refresh function into navigateToSeededRoute, added shouldRefreshDynamicData parameter to navigate function

Sequence Diagram

sequenceDiagram
    participant Client
    participant ServerActionReducer
    participant FetchServerAction
    participant Server
    participant NavigationSystem
    participant PPRNavigations
    participant CacheNode

    Client->>ServerActionReducer: Execute server action
    ServerActionReducer->>FetchServerAction: fetchServerAction(state, nextUrl, action)
    FetchServerAction->>Server: POST request with action
    Server-->>FetchServerAction: ActionFlightResponse {a, f, q, i, b}
    Note over Server,FetchServerAction: q: renderedSearch<br/>i: couldBeIntercepted
    
    FetchServerAction-->>ServerActionReducer: Return response data
    
    alt Has redirect
        ServerActionReducer->>Client: Reject promise with redirectError
    else No redirect
        ServerActionReducer->>Client: Resolve promise with actionResult
    end
    
    alt Has flight data
        ServerActionReducer->>NavigationSystem: navigateToSeededRoute(url, seedData, seedHead)
        NavigationSystem->>PPRNavigations: startPPRNavigation with seedData
        Note over PPRNavigations: Prefer seedData over prefetchData<br/>for consistency with server action writes
        PPRNavigations->>CacheNode: Create/update cache nodes
        PPRNavigations-->>NavigationSystem: Return navigation task
        NavigationSystem-->>ServerActionReducer: Return navigation result
    else No flight data but revalidated
        ServerActionReducer->>NavigationSystem: navigateUsingSegmentCache(shouldRefreshDynamicData=true)
        NavigationSystem->>PPRNavigations: Refresh dynamic data
        PPRNavigations-->>NavigationSystem: Return navigation task
        NavigationSystem-->>ServerActionReducer: Return navigation result
    else No changes
        ServerActionReducer-->>Client: Return unchanged state
    end
    
    ServerActionReducer-->>Client: Return updated router state
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants