Complete React Tutorial
Master React — build dynamic, component-driven UIs.
Getting Started with React
Install Node.js from nodejs.org. Create a React app with npx create-react-app my-app or use Vite for faster setup: npm create vite@latest my-app -- --template react. Navigate to the project folder and run npm start to launch development server on localhost:3000. Your React development environment is ready with hot reload, automatic transpilation, and a complete toolchain configured.
Introduction to React
React is a JavaScript library for building user interfaces with reusable components. It uses a virtual DOM for efficient updates and declarative component syntax. Build interactive UIs by composing small, focused components. React manages state and props automatically, triggering re-renders when data changes. Maintained by Facebook with excellent community support.
History of React
React was created by Facebook in 2013 and open-sourced in May 2013. Version 16 (2017) introduced render props and context. Hooks arrived in version 16.8 (2019), revolutionizing functional components. React 17 (2020) focused on compatibility. React 18 (2022) brought concurrent rendering, automatic batching, and Suspense. Current versions focus on performance and developer experience.
JSX Syntax
JSX is a syntax extension that looks like HTML in JavaScript. It gets transpiled to React.createElement() calls. Embed JavaScript expressions in curly braces. Use camelCase for attributes: className, onClick, onChange. JSX elements can have children and attributes. Multiple elements require a wrapper or fragment. JSX is compiled at build time with helpful error messages.
Components and Props
Components are reusable UI pieces accepting props as input. Props flow down the component tree (unidirectional). Props are read-only and should not be modified. Destructure props for cleaner code. Create default props with default parameters. Props enable flexible, reusable components. Pass callbacks through props for child-to-parent communication.
State and Lifecycle
State holds component data that changes over time. Updating state triggers re-renders. Class components use lifecycle methods like componentDidMount, componentDidUpdate, componentWillUnmount. Functional components use Hooks for the same functionality. Never mutate state directly; always create new objects. State is local to a component unless lifted up to parent.
React Hooks Overview
Hooks are functions that let you use React features in functional components without writing class components. Common hooks include useState for state management, useEffect for side effects, useContext for context consumption, useReducer for complex state, useCallback for memoized functions, and useMemo for memoized values. Custom hooks let you extract component logic into reusable functions that can be shared across components.
useState and useEffect
useState adds state to functional components. useEffect handles side effects like data fetching. Dependency array controls when effects run. Empty array = runs once on mount. Specific dependencies = runs when they change. Return cleanup function to prevent memory leaks. Multiple effects for multiple concerns. useEffect replaces lifecycle methods.
Context API
Pass data through component tree without prop drilling. Create context with React.createContext(). Provide values with Context.Provider. Consume with useContext hook. Useful for themes, authentication, language settings. Can become complex with many providers. Combine with useReducer for complex state. Context causes consumers to re-render when value changes.
React Router
Client-side routing for single-page apps. Define routes with Route component. Navigate with Link. useParams for route params. useNavigate for programmatic navigation. Nested routes for layout. Active links with NavLink. Route guards. Query strings. React Router enables navigation without page reloads.
Forms and Controlled Components
Build forms using controlled components where React state is the source of truth. Handle onChange events to update state. Use onSubmit for form submission. Validate data before submission. Implement error messages for invalid fields. Use FormData for file uploads. Uncontrolled components with refs are rarely needed. Controlled components ensure data flows through React state.
Event Handling
Handle events with camelCase handlers: onClick, onChange, onSubmit, onFocus, onBlur. Event handlers receive SyntheticEvent for cross-browser compatibility. Bind methods in class components or use arrow functions. Prevent default with e.preventDefault(). Stop propagation with e.stopPropagation(). Pass arguments with arrow functions. Event delegation improves performance.
Lists and Keys
Render lists with map(). Always provide unique key prop for list items. Never use array index as key if list can reorder. Keys help React identify changed items and maintain component state. Proper keys improve performance and prevent bugs. Missing keys cause console warnings. Keys are essential for list management and state preservation.
Conditional Rendering
Use ternary operators for simple conditions. Use logical AND (&&) for optional rendering. Use if-else for complex logic before return. Avoid rendering null or undefined unless intentional. Extract conditional logic into helper functions for readability. Create separate components for complex conditional branches. Conditional rendering keeps UI in sync with state.
Composition vs Inheritance
React favors composition over inheritance. Build complex UIs by combining simple components. Pass components as props for flexibility. Inheritance causes deep hierarchies and tight coupling. Composition enables reuse without shared parent. Props more powerful than inheritance. Avoid extending base classes. Composition provides more flexibility.
Refs and Direct DOM Access
useRef creates persistent object across renders. Access DOM with ref.current. Focus input, trigger animations, integrate third-party libraries. Use refs sparingly. Forward refs to child components. Refs are escape hatches for DOM access. Unmanaged components need refs. Store any mutable value in refs.
Higher-Order Components
HOCs reuse component logic by wrapping components. Function takes component, returns enhanced component. Use for authentication, theme, feature flags. Pass through props with spread operator. Display name for debugging. Can cause deeply nested trees. Hooks often better for code reuse. HOCs are advanced pattern for composition.
Render Props Pattern
Render props share code using function as child. Function receives data and returns JSX. More explicit data flow than HOC. Useful for animations, mouse tracking, form state. Can lead to nesting. Hooks often replace render props patterns. Read data and render pattern common with animations. Render props is a pattern for sharing code.
Error Boundaries
Class components that catch errors in child components. Implement componentDidCatch to log errors. Use getDerivedStateFromError() to update state. Display error UI to users. Functional error boundaries coming in React 19. Don't catch event handlers, async code, server rendering. Use error tracking services like Sentry.
Portals
Render children into different DOM node. Useful for modals, tooltips, dropdowns escaping parent CSS. Events bubble through React tree despite different DOM location. Create div in HTML for portal target. Close portals on Escape key. Manage z-index for stacking. Portals break out of component hierarchy.
Fragments
Fragments return multiple elements without wrapper div. Short syntax: <>. Useful when wrapper breaks CSS or DOM structure. No performance overhead vs div. Fragments support key and children props. Use for list groups, table rows, definition lists. Fragments keep DOM structure clean.
Code Splitting with Lazy and Suspense
Lazy load components with React.lazy(). Show fallback during load with Suspense. Improves initial bundle size. Use for route-based code splitting. Combine with error boundaries. Preload components for better UX. Works with Webpack, Vite, Parcel. Code splitting reduces initial load time.
Performance Optimization
Use React.memo to prevent unnecessary re-renders. useCallback for stable function references. useMemo for expensive calculations. Code splitting with React.lazy and Suspense. Image lazy loading. Debounce/throttle event handlers. Use React DevTools Profiler. Virtualize long lists. Optimize bundle size. Use production builds.
Testing React Components
Test with Jest and React Testing Library. Query elements with screen methods. Test user interactions, not implementation. Mock functions and modules. Async testing with waitFor(). Test coverage for critical paths. Integration tests better than unit tests. Snapshot testing catches regressions. Comprehensive testing ensures reliability.
State Management with Redux
Redux manages complex application state. Store is single source of truth. Actions describe changes. Reducers specify how state changes. Dispatch actions to update state. Use Redux for shared state across components. Redux Toolkit simplifies modern Redux. DevTools for debugging. Time-travel debugging.
Styling React Components
Inline styles use objects. CSS modules create scoped styles. CSS-in-JS libraries like styled-components. Tailwind CSS utility classes. Import regular CSS files. BEM methodology for CSS organization. CSS variables for theme consistency. Conditional styling with classNames library. Choose styling approach based on project needs and team preference.
TypeScript with React
Type props with interfaces. Type hooks with generics. Type event handlers. Type components with React.FC. Type children with React.ReactNode. PropsWithChildren for components. Excellent IDE support. Catches errors at compile time. Prevents runtime errors. TypeScript improves code quality.
React Best Practices
Keep components small and focused. Use meaningful names. Lift state appropriately. Pass data down, actions up. Use keys in lists. Memoize computations. Write tests. Follow conventions. Keep components pure. Avoid prop drilling. Handle errors. Optimize performance. Update dependencies. Best practices ensure maintainability.
Deployment
Build with npm run build. Optimize with code splitting and lazy loading. Deploy to Vercel, Netlify, AWS, or static hosting. Set up CI/CD with GitHub Actions. Configure environment variables. Set cache headers. Monitor performance. Use CDN. Enable compression. Set up error tracking. Monitor user experience.
Last updated: March 2026