refactor(optimization): Replace useOptimization with useOptimizationC…#352
Closed
Conversation
…ontext across components and hooks - Updated ControlPanel and CustomViewTracker components to utilize useOptimizationContext for SDK access. - Refactored hooks to ensure safe handling of SDK state, preventing errors when SDK is not ready. - Enhanced SSR compatibility by ensuring components and hooks return appropriate defaults when SDK is unavailable. - Improved overall code consistency and maintainability by standardizing SDK access patterns. This change streamlines the integration of the optimization SDK and enhances the robustness of the application during server-side rendering.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
OptimizationProvider returned null when isReady was false. On the server, useLayoutEffect never fires, so isReady never becomes true, and the provider always returned null — blank page on every SSR render.
Root cause
The original gate assumed "not ready = nothing to show." On the server that assumption is always true, so it silently stripped the entire subtree from HTML output.
The Fix
Flipped the question. Instead of "detect SSR and skip the gate," we asked "when should the gate actually fire?" — only on the client, after the provider has mounted.
A single hasMountedRef (flipped inside useLayoutEffect) tracks this. Gate condition becomes hasMountedRef.current && !isReady. On the server the ref stays false, children always render. On the client the gate fires normally until the SDK is ready. No SSR detection needed.
Why previous attempts failed
Every attempt tried to detect "server vs client" at render time — typeof window, useId tricks, isPreHydration refs — but React gives no clean signal at render time. The server render and the initial synchronous client render are indistinguishable. Every detection heuristic either broke jsdom, leaked state, or introduced extra re-renders.
Downstream surface area
With children now rendering on the server, SDK hooks called at render time would throw (sdk is undefined). Fixed the SDK's own internal hooks — useOptimizationActions, useOptimizationState (5 hooks), useEntryResolver, useMergeTagResolver, useAutoPageEmitter, NextjsOptimizationState — to read from useOptimizationContext() and safely default when sdk is undefined. useOptimization() public contract is unchanged.
Consumer code in nextjs-sdk_ssr and nextjs-sdk_hybrid that called useOptimization() at render time was updated to use useOptimizationContext() with a sdk guard — same pattern the SDK now uses internally.
What we chose not to do
Validation