In 2026, Angular same detail page changes id but content doesn't update, and refresh fixes it—is it API caching?
In an Angular project, when you click from a list into another detail page, the URL params change but the content does not. Most of the time this is not API caching; the component instance is being reused under the same route configuration: ngOnInit runs only on first entry, and snapshot still reads the params from the first entry. A time-saving triage step is to refresh the page manually—if it works after refresh, you can basically investigate along this path.
When the URL changes but content does not, it is usually not API caching
Under Angular Router's default reuse strategy, as long as two navigations hit the same route configuration (for example, /product/:id), the framework treats it as the same page. It does not destroy the old component or create a new instance; it only updates the param values on ActivatedRoute. If the component reads params only once during initialization, all later clicks still read the old values.
Making this distinction clearly matters. Many teams instinctively check API and browser caches, wasting a round during integration; once component reuse is confirmed, the fix is fairly certain.
- ngOnInit runs only once: Param changes under the same route do not trigger a new initialization hook, so putting all data loading inside it will miss updates.
- snapshot reads the value at that moment: route.snapshot.paramMap is read once when entering the component and does not change with later params.
- Refresh rebuilds: A browser refresh is equivalent to re-entering the app, so the component is recreated and the problem appears to disappear.
- The same applies to query params: Changing only ?keyword=xx on the same route still counts as the same route, and the component is reused under the default strategy.
One action provides initial triage
Refresh the page manually once: if the content is correct after refresh, suspect component reuse and param-reading first; if it is still wrong after refresh, look into API caching, CDN, or server-side caching. This saves time during integration and prevents frontend and backend from blaming each other.
Three-step localization: route layer, lifecycle layer, data source layer
Fixing the troubleshooting order is faster than guessing one by one. Check these three layers in order and do not skip steps; skipping easily leads to misjudgment—for example, the route actually changed the component, but you keep changing how params are read.
- Route layer: First confirm whether this navigation hits the same parameterized route configuration, and whether the project has introduced a custom RouteReuseStrategy. The passing standard is being able to say directly whether it is the same component instance.
- Lifecycle layer: Then check whether params are read with snapshot in ngOnInit or by subscribing to paramMap. The former reads only once on entry; the latter pushes repeatedly as params change.
- Data source layer: Finally confirm whether a new request is actually made after receiving new params. A common short-circuit is returning immediately if data already exists, or using a component-level temporary cache.
Each layer has its own pitfalls: the route layer easily ignores query param changes; the lifecycle layer easily has subscriptions written in the constructor, outside the injection context; the data source layer easily mistakes API-layer caching for component caching. After checking all three, you can usually locate which link is broken.
Comparison of two common fixes: subscribe to the param stream or let the component rebuild
In 2026, common approaches mainly fall into two paths. Their costs differ, so do not default to the one with the smaller change surface.
- Option A, subscribe to the param stream: Subscribe to paramMap or queryParamMap in ngOnInit, and re-fetch data when params change. Changes stay inside the page, the component instance is preserved, and scroll position and some state are not lost. Pay attention to subscription cleanup timing; newer versions can use patterns like takeUntilDestroyed to close it out.
- Option B, rebuild the component when params change: Return no reuse from a custom RouteReuseStrategy, or add a key to the router outlet so different keys map to different outlets. The change surface may cover a whole area, but page state resets naturally, which suits inherently stateless detail pages.
Another approach is to pre-fetch data with a resolver before entering the route, so data is ready when the component initializes. The cost is a longer first-screen wait, which is more noticeable on weak networks; it is better for scenarios with small data volume that display immediately on entry.
Ranking these three approaches by delivery cost gives a checkable set of typical experience ranges:
- Adjusting only one page's param-reading pattern: typical range 0.5–1 person-day.
- Also handling scroll position restoration, preserving list state on return, and form draft processing: typical range 1–3 person-days.
- Changing the global reuse strategy: impact spreads with the number of routes, usually requiring a full-site regression round, typical range 2–5 person-days.
The difference mainly comes from how much internal state the page has, not from the framework itself. The ranges above are estimated by page shape; actual effort is also affected by team familiarity and regression scope.
Delivery scene: a rework from list to detail
A common situation: the list navigates to detail, the detail page uses snapshot to get the id, and everything works on first entry. Later a 'related recommendations' module is added; clicking a recommendation still lands on the same route, just with a different id, and the page does not move at all. When QA files the defect, developers first suspect API caching because a single refresh fixes it. At the time the constraint was only two days left in the schedule, and the detail page still had to preserve scroll position and return state. The fix was to change param reading to subscribe to the param stream, reset local state in the callback, and add a loading state; the cost was half a day of rework plus a regression round, and adding a 'same route, different params' test case. In the project retrospective, this kind of rework was attributed to the same missing premise: when entering the detail page, param changes were not treated as the default case.
Applicable and non-applicable boundaries
For pages whose params change, handling them as a param stream is more stable. Typical cases are list-to-detail, switching id or Tab under the same route, and switching filter conditions via query params; in these scenarios, param changes are the norm rather than the exception.
- Suitable for param-stream handling: The page is relatively stateless, params switch frequently, and you want to preserve scroll position or return state.
- Suitable for component rebuild: The page has a lot of one-time initialization, such as map instances, editors, or complex form drafts; rebuilding also clears dirty state.
- No extra handling needed: For static detail pages whose params are determined only before entry and do not switch again within the page, using snapshot does not cause errors; forcibly changing to a subscription only adds code noise.
- Where to be careful: A custom RouteReuseStrategy affects overall route behavior; changing the global strategy for just one page can easily break return state and scroll position on other pages.
Acceptance criteria can be defined in three statements: entering the same route with different params must update page data; returning from detail to list and entering again must match expected scroll position and filter conditions; refresh entry and route entry must produce consistent results. Only after these three pass does it make sense to discuss animation and performance optimization. Check specific implementation against the official documentation for your Angular version and your team's acceptance checklist.
FAQ
If manually refreshing the page fixes it, does that prove route reuse?
Most likely yes. Refresh recreates the component and re-reads params, so the content recovers; however, you still need to rule out the entry HTML being cached by the browser, since the two look similar.
What exactly is the difference between snapshot and subscribing to paramMap?
snapshot is the value at the moment of entering the component and does not update when params change later; subscribing to the param stream pushes new values on every param change, which suits pages whose params change.
If only query params change, does the same route still reuse the component?
Under the default strategy, yes—it still counts as the same route configuration. Switch to subscribing to queryParamMap, or let the component rebuild when params change.
Does using OnPush make this problem more obvious?
These are two separate issues. OnPush affects whether change detection is triggered; route reuse affects whether the component is rebuilt and whether param reading updates. Confirm them separately during troubleshooting.
What is the cost of forcing the component to rebuild?
The page's internal state, scroll position, and already loaded data are all reset, and animations and requests run again. The impact is small for stateless pages; for complex pages, plan state restoration in advance.
When you encounter this kind of symptom, first use page refresh as a triage action, then localize through the three checks: route layer, lifecycle layer, and data source layer. Write pages with changing params as a param stream, and pages with fixed params with snapshot; do not touch the global route strategy just for stylistic consistency. Angular versions differ significantly, so before implementing in 2026, verify again against the official documentation and your team's acceptance checklist.
-
An H5 campaign page embedded in Flutter scrolls rough on Android—which layer should you touch first?
Date: Oct 14, 2026 Read: 5
-
It's 2026 and the page title isn't in the source code — where does Baidu get the indexed title?
Date: Oct 13, 2026 Read: 9
-
OnPush child component not refreshing with polling data in Angular: replace the array reference first, or add markForCheck first?
Date: Oct 12, 2026 Read: 14
-
It's 2026, two dialogs in Vue share the same composable—one fails to submit and the other also shows an error. Is state leaking?
Date: Oct 11, 2026 Read: 31
-
It's 2026 — why does await inside forEach send all requests before waiting for results?
Date: Oct 9, 2026 Read: 23




