ESLint: Hooks must be the same function on every render, but this value may change over time to a different function.
See https://react.dev/reference/rules/react-calls-components-and-hooks#dont-dynamically-use-hooks (react-compiler/react-compiler)React Compiler
Migrate useCallStateHooks() usage for React Compiler compatibility.
React Compiler enforces stricter hook constraints for build-time optimization. eslint-plugin-react-compiler reports incompatible patterns.
Problem
Calling useCallStateHooks() inside components violates React Compiler's static analysis:
Why this breaks with React Compiler
useCallStateHooks() is a factory function, not a hook. Calling it inside components creates hook references during render that React Compiler cannot statically verify.
Solution
Call useCallStateHooks() once at module scope, then use destructured hooks in components.
Migration pattern
- Alias import as
getCallStateHooks - Call factory at module scope
- Destructure hooks at top level
- Use hooks in components
What not to do
Don't call the factory inside components:
import { useCallStateHooks as getCallStateHooks } from "@stream-io/video-react-native-sdk";
const MyComponent = () => {
const hooks = getCallStateHooks(); // ❌ still dynamic, still triggers error
const { useCallCallingState } = hooks;
// ...
};Before / After
Before:
import { useCallStateHooks } from "@stream-io/video-react-native-sdk";
import { View, Text } from "react-native";
const MyComponent = () => {
const { useCallCallingState, useParticipants } = useCallStateHooks();
const callingState = useCallCallingState();
const participants = useParticipants();
return (
<View>
<Text>State: {callingState}</Text>
<Text>Participants: {participants.length}</Text>
</View>
);
};After:
import { useCallStateHooks as getCallStateHooks } from "@stream-io/video-react-native-sdk";
import { View, Text } from "react-native";
const { useCallCallingState, useParticipants } = getCallStateHooks();
const MyComponent = () => {
const callingState = useCallCallingState();
const participants = useParticipants();
return (
<View>
<Text>State: {callingState}</Text>
<Text>Participants: {participants.length}</Text>
</View>
);
};Why alias to getCallStateHooks
Required because ESLint treats use* functions as hooks that cannot be called outside components. The alias clarifies it's a factory function.
Automated Migration with Codemod
Use @stream-io/video-codemod for automatic transformation.
Usage
npx @stream-io/video-codemod use-call-state-hooks ./src \
--extensions=ts,tsx \
--parser=tsx \
--run-prettier # optional, runs prettier on the transformed files