Chapter 16: Acceptance: Making React Work for You (Not the Other Way Around)
You’ve been through denial (“React isn’t that complicated”). You’ve experienced anger (“Why does useEffect run twice?!”). You’ve bargained (“Maybe if I just use Next.js…”). You’ve felt the depression (“node_modules is 2GB for a counter”).
Now, welcome to acceptance. Not defeat. Not surrender. Acceptance.
Choosing Your Battles
The first step to React sanity is knowing which battles to fight and which to accept.
Battles Not Worth Fighting
The Build System Wars
// Stop doing this
// webpack.config.js - 500 lines of configuration
// Just do this
npm create vite@latest
// or
npx create-next-app
The build system will be complex. You will not understand it fully. That’s okay. Use a tool that hides it and move on.
The Perfect Component Structure
// Stop obsessing over this
/components
/atoms
/molecules
/organisms
/templates
/pages
/universe
YourComponent.jsx
// Just do this
/components
YourComponent.jsx
Flat is fine. Nested is fine. Whatever your team agrees on is fine. Stop reorganizing.
The State Management Crusade
// You don't need Redux for everything
const [count, setCount] = useState(0); // This is fine
// You don't need Context for everything
<Parent data={data}>
<Child data={data} /> // Prop drilling 2 levels is fine
</Parent>
Use the simplest solution that works. Add complexity only when pain demands it.
Battles Worth Fighting
Bundle Size
// Worth fighting
import { debounce } from 'lodash'; // 70KB for one function
// Do this instead
import debounce from 'lodash/debounce'; // 2KB
// Or better
const debounce = (fn, ms) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), ms);
};
};
Unnecessary Re-renders
// Worth fixing if it's actually slow
const ExpensiveList = React.memo(({ items }) => {
return items.map(item => <ExpensiveItem key={item.id} {...item} />);
});
// Not worth fixing if it's fast enough
const SimpleList = ({ items }) => {
return items.map(item => <div key={item.id}>{item.name}</div>);
};
Developer Experience
// Worth investing in
- TypeScript (when team knows it)
- Prettier (no more style debates)
- ESLint (catch bugs early)
- Good error boundaries (users see errors gracefully)
// Not worth obsessing over
- Perfect test coverage
- Zero ESLint warnings
- Cutting-edge React features
The Features That Actually Help
After all the complaining, here are React features that genuinely improve development:
Component Composition
// This is actually good
<Layout>
<Header />
<MainContent>
<Article />
<Sidebar />
</MainContent>
<Footer />
</Layout>
Breaking UI into components does help organize code, even if we’ve taken it too far.
Declarative Rendering
// This is clearer than imperative
return isLoggedIn ? <Dashboard /> : <Login />;
// Than this
if (isLoggedIn) {
document.getElementById('root').innerHTML = dashboardHTML;
} else {
document.getElementById('root').innerHTML = loginHTML;
}
Describing what UI should look like based on state is intuitive, even if the implementation is complex.
The Ecosystem (When Used Wisely)
// These actually save time
- Next.js (when you need SSR)
- React Query (for server state)
- React Hook Form (for complex forms)
- Tailwind (if you like it)
// These don't
- Another state management library
- Another CSS-in-JS solution
- Another testing utility
- Another anything you already have
Building Your Own Conventions
The key to React sanity is establishing conventions and sticking to them:
File Structure Convention
/src
/components # Shared components
/pages # Page components
/hooks # Custom hooks
/utils # Utilities
/api # API calls
Simple. Boring. Works.
Component Convention
// Every component follows same pattern
import React from 'react';
import styles from './Component.module.css';
export const Component = ({ prop1, prop2 }) => {
// Hooks at top
const [state, setState] = useState();
// Effects next
useEffect(() => {}, []);
// Handlers
const handleClick = () => {};
// Render
return <div>Content</div>;
};
State Convention
// Local state for UI
const [isOpen, setIsOpen] = useState(false);
// Server state with React Query
const { data } = useQuery(['todos'], fetchTodos);
// Global state only when truly global
const theme = useContext(ThemeContext);
// No Redux unless you actually need it (you probably don't)
Finding Peace in the Chaos
Accept the Re-renders
// This will re-render. It's fine.
const Parent = () => {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>+</button>
<Child /> {/* Will re-render. It's fine. */}
</>
);
};
React re-renders. A lot. Unless it’s measurably slow, let it.
Accept the Complexity
// Your package.json will be huge
"dependencies": {
// 50+ packages
}
// Your node_modules will be massive
// 1GB+
// Your build will be slow
// 30+ seconds
// Accept it and move on
This is modern web development. Fighting it is futile.
Accept the Abstractions
// You're not writing HTML
<div className="container"> {/* It's className, not class */}
// You're not writing JavaScript
{items.map(item => <Item key={item.id} />)} {/* It's JSX */}
// You're not updating the DOM
setState(newState); {/* React updates the DOM */}
// Accept the abstraction layer
The Productive React Developer
Here’s how to actually be productive with React:
1. Stop Optimizing Prematurely
// Write simple code first
const SimpleComponent = ({ data }) => {
return <div>{data.map(item => <div>{item}</div>)}</div>;
};
// Optimize only when profiler shows it's slow
const OptimizedComponent = React.memo(({ data }) => {
const memoizedData = useMemo(() => processData(data), [data]);
return <div>{memoizedData.map(item => <div>{item}</div>)}</div>;
});
2. Use Boring Technology
// Boring but works
- React (not the latest beta)
- React Router (v6 is fine now)
- CSS Modules or plain CSS
- Fetch or Axios
- Jest for testing
// Exciting but painful
- React Canary builds
- That new experimental router
- That CSS-in-JS library with 5 GitHub stars
- That GraphQL client everyone's hyping
- That new test runner that's "faster"
3. Ship Features, Not Architecture
// Users care about this
- Does it work?
- Is it fast enough?
- Does it look good?
// Users don't care about this
- Your component structure
- Your state management
- Your test coverage
- Your build system
4. Know When to Break the Rules
// Sometimes imperative is fine
const inputRef = useRef();
inputRef.current.focus(); // Direct DOM manipulation! Scandal!
// Sometimes inline styles are fine
<div style=>
// Sometimes any is fine (in TypeScript)
const data: any = await fetch('/api/data'); // Fight me
// Sometimes no tests are fine
// That component that renders text? It doesn't need a test.
The Middle Way
The secret to React happiness is finding the middle way:
- Use React’s patterns, but don’t obsess over them
- Follow best practices, but know when to break them
- Optimize performance, but only what matters
- Write tests, but not for everything
- Use TypeScript, but allow
any
when needed - Create abstractions, but not too many
- Update dependencies, but not immediately
Your React Survival Kit
// The only React you really need to know
import React, { useState, useEffect } from 'react';
// Component
const Component = ({ props }) => {
// State
const [state, setState] = useState();
// Effects
useEffect(() => {
// Do something
return () => {
// Cleanup
};
}, []);
// Render
return <div>JSX</div>;
};
// That's 90% of React right there
The Final Acceptance
React is not perfect. It’s not even good, necessarily. But it’s:
- Ubiquitous - Everyone uses it
- Employable - Jobs everywhere
- Supported - Huge ecosystem
- Documented - Solutions exist
- Evolving - Getting better (slowly)
You don’t have to love React. You don’t have to defend it. You don’t have to evangelize it.
You just have to use it productively, ship features, and go home.
The Path Forward
You know React now. You understand its flaws. You’ve accepted its reality. You can:
- Build things - Despite the complexity
- Ship products - Despite the overhead
- Get paid - Despite your preferences
- Stay sane - Despite everything
The Zen of React
The Virtual DOM is not real.
Components are just functions.
Hooks are just closures with rules.
State is just variables with notifications.
Props are just arguments.
JSX is just function calls.
React is just JavaScript.
Complicated JavaScript.
With a lot of opinions.
And a huge ecosystem.
And too many abstractions.
But still just JavaScript.
And you know JavaScript.
So you know React.
Even if you hate it.
Welcome to acceptance. It’s not giving up. It’s not giving in. It’s understanding the game and playing it well enough to win.
Now go build something. Ship it. Get paid. Go home.
And try not to think about the node_modules folder.
It’s fine.
Everything is fine.
This is fine.
🔥🐕☕🔥
(This is fine.)