Getting Started With React

React is a JavaScript library for building user interfaces. That's the standard definition you'll see everywhere. The thing people don't tell you upfront is that it's a library, not a framework. You still need to bring your own build tooling, routing, state management, and usually a CSS strategy. React will handle the DOM updates. Everything else is on you. The most common mistake I see is people trying to write React before they're comfortable with modern JavaScript. Specifically arrow functions, destructuring, array methods like map and filter, and template literals. If you're still writing jQuery-style DOM manipulation or defining components with function declarations instead of arrow syntax, you're going to struggle and it'll look like React is the problem when it isn't. I had a developer come to me last year who was frustrated that his components kept re-rendering infinitely. He'd written a useState initializer that called an expensive API function directly in the argument. Every render triggered a new fetch, which triggered a state update, which triggered another render. The fix was wrapping it in a useCallback dependency or moving the call into a useEffect. Takes about five minutes to explain but three days for someone to untangle it themselves.

Setting Up Your First Project

The official way to start is with create-react-app or the Vite approach. Vite is faster and has less legacy baggage. Node 18 or later, npm or pnpm, then run the setup command. It generates a project structure with a dev server, hot module replacement, and a basic component file already in place. Inside that structure, the key files are index.html as the entry point, main.jsx or main.tsx importing React and mounting to the DOM, and App.jsx containing your root component. From there you create folders for components, hooks, and utilities. Don't overthink it at first. A flat components folder works fine until you hit around fifty files, then splitting by feature becomes necessary.

Components and JSX

JSX looks like HTML inside JavaScript. It compiles down to React.createElement calls. You write it, Babel or SWC transforms it during build. The result is a component tree that React can diff against previous renders and update only what changed. Components are either functions or classes. Function components with hooks are the standard now. Class components exist in legacy codebases and you'll encounter them in older projects at work. They serve the same purpose but carry more boilerplate. Stick to functional components unless you have a reason not to. Props are how you pass data down. They're read-only. If a child needs to communicate changes back up, the parent passes a callback prop. This unidirectional data flow is one of React's core principles and it keeps bug sources predictable. Breaking it by mutating props directly causes warnings and confusing state bugs.

State Management

useState handles local component state. useReducer is for complex state logic with multiple sub-values. Context API avoids prop drilling when values need to reach deep descendants. For anything beyond that—global app state, server synchronization, caching—you'd typically add a library like Zustand, Redux Toolkit, or TanStack Query. The common trap is putting everything in global state. A loading spinner, a theme toggle, a form input value—all of it in a single store. That creates unnecessary re-renders and makes debugging harder. Keep state close to where it's used. Lift it up only when multiple components need access. I ran into a situation once where a form component was re-rendering every keystroke because its parent had a state object containing fifty unrelated fields. Moving individual fields into separate useState calls inside the form component cut render time from roughly 120ms to about 8ms on a mid-range laptop. Not a dramatic improvement on paper but noticeable when typing fast.

Side Effects With useEffect

useEffect runs after render for things like data fetching, subscriptions, or manual DOM manipulation. The dependency array controls when it re-runs. Empty array means run once after mount. Missing dependencies cause stale closures. Adding too many causes infinite loops if the effect triggers a state update. A practical rule: if your effect doesn't need cleanup, don't write a cleanup function. If it does, make sure the cleanup actually prevents memory leaks. I've seen useEffect hooks that subscribed to events but never unsubscribed in production builds, leaving handlers attached for the lifetime of the page. Browser task manager would show the leak but runtime behavior stayed fine until the app grew large enough to matter.

Performance Considerations

React optimizes most things automatically. You rarely need to worry about it. But when you do, React.memo prevents unnecessary re-renders on components receiving unchanged props. useMemo caches expensive calculations. useCallback stabilizes function references for dependency arrays. These are optimizations, not requirements, and misusing them can make code harder to read without meaningful gains. The biggest performance win is usually just reducing render count by restructuring components, not by adding memo. A component that only renders when its own state changes is already optimal. Wrapping it in React.memo adds nothing. Removing a parent component that re-renders on every keystroke because it holds unrelated state is where the real improvement happens.

Routing

React Router is the standard. v6 changed the API significantly from v5 so tutorials using older versions will confuse you. The current approach uses and elements with path matching. Nested routes use Outlet components. Data fetching moved into loaders rather than effects inside components. For small projects you can get away with client-side routing only. For larger apps with server-rendered content or SEO requirements, Next.js provides built-in routing and rendering strategies. It's a separate ecosystem built on top of React and learning it adds complexity but removes configuration decisions.

Common Pitfalls

Conditional rendering with && breaks if the left side is zero. Use a ternary or wrap in parentheses. Boolean logic with null and undefined in JSX returns errors sometimes. Avoid mixing state updates in the same render cycle without batching. React 18 handles automatic batching but manual batching is worth understanding for edge cases. Another issue is treating React like a full framework and expecting it to solve problems it wasn't designed for. It doesn't manage HTTP requests, it doesn't handle routing natively, it doesn't enforce architectural patterns. These are all valid concerns but they require additional tools. Accepting that early saves weeks of frustration trying to make React do something it explicitly doesn't do.

Where to Go Next

After the basics, pick a direction. Frontend architecture with state management libraries, server-side rendering with Next.js, or mobile development with React Native. Each has its own ecosystem and learning curve. The foundation stays the same but the surrounding tooling changes significantly. There's no complete React User Guide For Beginners because the ecosystem moves too fast. Documentation at react.dev is the current authoritative source and it's freely available. Third-party tutorials become outdated within months on version-specific topics but the core concepts remain stable. Focus on understanding why React works the way it does rather than memorizing syntax patterns that may change between versions.