See exactly why your React Native components re-render.
Components flash on re-render. A badge tells you why. No more guessing.
Ever stared at your React Native app and asked:
- "Why is this re-rendering?"
- "Why is my FlatList so laggy?"
- "Which prop is causing this?"
React Native doesn't tell you. The Profiler gives you timing, not reasons. Console logs don't show you where.
WhyRN does.
It highlights re-renders on screen, shows the exact reason β which prop changed, which state updated, whether it's a new reference or a real value change β and paints a heatmap so you can spot the hottest components instantly.
- π Highlights re-renders in real time β components flash with a colored border
- π§ Shows exact reason β props, state, hooks, or parent re-render
- π Props diff β distinguishes reference change vs value change
- π‘οΈ Heatmap mode β cold (blue) to hot (red) based on render frequency
- β‘ Zero config β wrap your app, done
- π± React Native first β built for mobile, not a web port
- πͺΆ Zero dependencies β only React and React Native as peers
- π Dev only β no-op in production, tree-shaken away
npm install whyrn.devyarn add whyrn.devimport { WhyRN } from 'whyrn.dev';
export default function App() {
return (
<WhyRN>
<YourApp />
</WhyRN>
);
}That's it. No init function, no config files, no babel plugins.
Every component that re-renders will flash on screen with a badge showing the reason.
When a component re-renders, you see this in the console:
π UserCard re-rendered (#4)
prop "user" changed (new reference, same value)
state[0] changed: 1 β 2
And on screen:
ββββββββββββββββββββββββββββββββ
β UserCard β props: user β β badge
ββββββββββββββββββββββββββββββββ€
β β
β ββββ red border ββββ β β flash overlay
β β β β
β β UserCard β β
β β β β
β βββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββ
Don't want to track everything? Use the HOC:
import { withWhyRN } from 'whyrn.dev';
function UserCard({ user }) {
return <Text>{user.name}</Text>;
}
export default withWhyRN(UserCard);Or the hook, for full control:
import { useWhyRN } from 'whyrn.dev';
function UserCard(props) {
const reasons = useWhyRN('UserCard', props);
// reasons = [{ type: 'props', propChanges: [...] }]
return <Text>{props.user.name}</Text>;
}See which components render the most β cold (blue) means few renders, hot (red) means many:
<WhyRN heatmap>
<YourApp />
</WhyRN>The border color shifts based on render frequency in a 5-second sliding window.
All options are passed as props. Every prop is optional.
<WhyRN
enabled={__DEV__} // Kill switch (default: __DEV__)
trackHooks // Track useState/useReducer (default: true)
logToConsole // Log to console (default: true)
heatmap // Heatmap mode (default: false)
flashDuration={600} // Flash duration in ms (default: 600)
flashColor="#FF6B6B" // Flash border color (default: #FF6B6B)
heatmapColdColor="#3B82F6" // Heatmap cold color (default: #3B82F6)
heatmapHotColor="#EF4444" // Heatmap hot color (default: #EF4444)
include={[/Screen/, /Card/]} // Only track matching names (default: [])
exclude={[/^RN/, /^RCT/]} // Skip matching names (default: RN internals)
>
<YourApp />
</WhyRN>Root provider. Wraps your app to enable visual overlays and auto-tracking.
HOC that tracks a specific component. Works with or without <WhyRN> β without the wrapper, it logs to console only.
Hook that returns an array of RenderReason objects for the current render. Useful for custom debugging UI or logging.
Simple hook that returns how many times the component has rendered. Optionally logs to console.
| Feature | why-did-you-render | React DevTools | WhyRN |
|---|---|---|---|
| React Native support | β | β | |
| Visual overlay | β | β Flash + badge | |
| Shows why | β | β On screen | |
| Props diff | β | β | β |
| Reference vs value | β | β | |
| Heatmap | β | β | β |
| Zero config | β Needs init + babel | β | β |
| Hook tracking | β | β | β |
<WhyRN>patchesReact.createElementon mount to wrap tracked components with a thin HOC- The HOC stores previous props in a
useRefand diffs on every render - When a re-render is detected, it calls
measureInWindowto get the component's screen position - A global overlay renders an
Animated.Viewborder that fades out, plus a reason badge - In heatmap mode, the border color is computed from the render rate in a sliding window
Since we only care about re-renders (not the first render), patching at mount time is fine. The library is a complete no-op when __DEV__ is false.
- React 18+
- React Native 0.70+
- Hermes or JSC
- Expo Snack playground
- State variable name extraction (babel plugin)
- Flipper / DevTools integration
- Per-component render timeline
- Re-render count badge overlay
- Context tracking with provider name
Contributions are welcome! Please open an issue first to discuss what you'd like to change.
MIT
If WhyRN helps you debug faster, consider giving it a β
github.com/vladbars/whyrn

