[compiler]: add useWindowVirtualizer to known incompatible libraries
Project: facebook/react | Language: JavaScript | Concepts: api-design, backwards-compatibility | Difficulty: mid
Link: https://github.com/react/react/pull/36912
The problem
The React compiler tracks certain hooks from third-party libraries that are known to break memoization, marking them as incompatible so users are warned. Previously, only useVirtualizer from @tanstack/react-virtual was marked this way, but its sibling hook useWindowVirtualizer—which has the same problematic behavior—was not. This meant code using useWindowVirtualizer could silently break, leading to bugs like virtualized lists being stuck empty.
Why it's non-trivial
A naive fix might only address the hook that was reported (useVirtualizer) and miss that useWindowVirtualizer is a thin wrapper around the same internal logic, returning the same referentially-stable but internally-mutated object. Both need to be marked as incompatible to prevent subtle, hard-to-diagnose bugs.
The approach
Type provider update in Rust:
+ // `useWindowVirtualizer()` wraps the same virtualizer instance as `useVirtualizer()`,
+ // so its return value is incompatible for the same reason.
+ (
+ "useWindowVirtualizer".to_string(),
+ TypeConfig::Hook(HookTypeConfig {
+ positional_params: Some(Vec::new()),
+ rest_param: Some(Effect::Read),
+ return_type: Box::new(TypeConfig::TypeReference(TypeReferenceConfig {
+ name: BuiltInTypeRef::Any,
+ })),
+ return_value_kind: None,
+ no_alias: None,
+ aliasing: None,
+ known_incompatible: Some(
+ "TanStack Virtual's `useWindowVirtualizer()` API returns functions that cannot be memoized safely".to_string(),
+ ),
+ }),
+ ),
This snippet adds useWindowVirtualizer to the set of known-incompatible hooks in the Rust implementation of the module type provider. The configuration mirrors the existing entry for useVirtualizer, including the incompatibility warning.
Type provider update in TypeScript:
+ /*
+ * `useWindowVirtualizer()` wraps the same virtualizer instance as `useVirtualizer()`, so its return value
+ * is incompatible for the same reason and we mark the entire hook as incompatible
+ */
+ useWindowVirtualizer: {
+ kind: 'hook',
+ positionalParams: [],
+ restParam: Effect.Read,
+ returnType: {kind: 'type', name: 'Any'},
+ knownIncompatible: `TanStack Virtual's \`useWindowVirtualizer()\` API returns functions that cannot be memoized safely`,
+ },
This snippet updates the JavaScript/TypeScript module type provider in the same way, ensuring both the Rust and JS implementations are in sync. The comment explains the rationale for the addition.
From the review thread
No notable review discussion on this PR.
Takeaways
- When marking third-party APIs as incompatible with a system (like memoization), audit for all variants and wrappers, not just the most obvious or commonly used entry point.
- Keep parallel implementations (e.g., Rust and JS/TS) in sync for configuration changes to avoid inconsistencies or platform-specific bugs.
- Document the rationale for incompatibility directly in code comments to aid future maintainers and reviewers.