A focused React performance demo that illustrates expensive computations, re-renders, and how useMemo prevents unnecessary recalculation when unrelated state changes.
This project is intentionally simple and educational, designed to clearly show when expensive logic runs and when it should not.
π https://react-expensive-calculation-memo.vercel.app
This project is automatically deployed using Vercel with GitHub integration.
- Every push to
maintriggers a production deployment - Pull requests generate preview deployments
- Build, optimization, and hosting are handled by Vercel
This app renders:
- An expensive Fibonacci calculation
- An input that controls the calculation (
Fibonacci N) - An unrelated text input
- A memoized list of selectable items (
Apple,Banana,Orange,Mango)
By interacting with the UI and observing the console logs, you can clearly see:
- When the expensive calculation runs
- When components re-render
- When memoization prevents unnecessary work
The Fibonacci calculation is intentionally slow:
const slowFibonacci = (n: number): number => {
if (n <= 1) return n;
return slowFibonacci(n - 1) + slowFibonacci(n - 2);
};This simulates a CPU-heavy operation often found in real applications (data processing, large calculations, complex transforms).
The result is memoized so it only recomputes when n changes:
const result = useMemo(() => {
console.time("fib");
const value = slowFibonacci(n);
console.timeEnd("fib");
return value;
}, [n]);What this achieves:
- Changing unrelated input does NOT re-run Fibonacci
- Only changing
Fibonacci Ntriggers recalculation - Performance impact is visible via
console.time
Both the result display and the item list are memoized:
const ResultCard = memo(function ResultCard({ value }: ResultCardProps) {
console.log("ResultCard rendered");
return <div>Result: {value}</div>;
});const SlowList = memo(function SlowList({ onSelect }: SlowListProps) {
console.log("SlowList rendered");
...
});This prevents unnecessary UI re-renders when props are stable.
The item click handler is memoized:
const handleSelect = useCallback((name: string) => {
console.log("Selected:", name);
}, []);Without this, memoized child components would still re-render due to changing function references.
This demo intentionally keeps console.log and console.time statements.
They are essential to the learning goal:
- Typing in Unrelated input β Fibonacci does NOT run
- Changing Fibonacci N β Fibonacci runs again
- Selecting items β Only selection logs appear
- Memoized components remain stable
β οΈ Removing the logs would make the demo significantly less educational.
In small demos, expensive calculations are harmless.
In real-world apps, they can cause:
- UI freezes
- Janky interactions
- Poor user experience
This project demonstrates:
- Why expensive computations must be controlled
- How
useMemoisolates costly logic - How to prove performance improvements, not assume them
It is a proof of concept, not a production-ready calculator.
react-expensive-calculation-memo/
ββ src/
β ββ components/
β β ββ ExpensiveCalculator.tsx
β β ββ ResultCard.tsx
β β ββ SlowList.tsx
β β ββ Item.tsx
β ββ App.tsx
β ββ main.tsx
ββ public/
ββ index.html
ββ README.md
npm install
npm run dev
# open http://localhost:5173- React StrictMode is enabled
- In development, React intentionally double-renders
- This is expected behavior
- Production builds render only once
This demo is StrictMode-safe.
Try the following experiments:
- Remove
useMemoβ watch Fibonacci run on every keystroke - Remove
useCallbackβ observe list re-renders - Remove
React.memoβ observe UI instability - Increase Fibonacci N β feel the performance cost
This project is licensed under the MIT License.