Master React.js
From Newbie to Professional
Build Your Front-End Development Career
Authored by William H. Simmons
Founder of A Few Bad Newbies LLC
React.js Professional Development Course
Module 1: React Fundamentals
Chapter 1: Introduction to React
React is a JavaScript library for building user interfaces, focusing on component-based architecture.
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return <div className="text-blue-500">Hello, React!div>;
}
ReactDOM.render(<App />, document.getElementById('root'));
Common Mistakes
- Forgetting to import React.
- Using
classinstead ofclassNamein JSX.
Chapter 2: JSX and Elements
JSX is a syntax extension for JavaScript that allows HTML-like code in React.
const element = <h1 className="text-xl text-blue-500">Hello, JSX!h1>;
// Equivalent to:
const element = React.createElement('h1', { className: 'text-xl text-blue-500' }, 'Hello, JSX!');
Pro Tip
Use camelCase for JSX attributes (e.g., className) to align with JavaScript conventions.
Chapter 3: Components and Props
Components are reusable building blocks in React, accepting props as inputs.
function Welcome(props) {
return <h1 className="text-lg text-blue-400">Hello, {props.name}h1>;
}
function App() {
return (
<div className="p-4">
<Welcome name="Alice" />
<Welcome name="Bob" />
div>
);
}
Common Mistakes
- Mutating props directly.
- Not providing unique
keyprops for lists.
Module 2: State and Lifecycle
Chapter 1: Managing State
State allows components to manage dynamic data and re-render when it changes.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<div className="p-4 text-blue-500">
<p>Count: {this.state.count}p>
<button className="bg-blue-500 text-white p-2 rounded" onClick={() => this.setState({ count: this.state.count + 1 })>
Increment
button>
div>
);
}
}
Pro Tip
Always use setState to update state, never modify this.state directly.
Chapter 2: Component Lifecycle
Lifecycle methods allow you to hook into component mounting, updating, and unmounting.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { time: new Date() };
}
componentDidMount() {
this.timer = setInterval(() => this.setState({ time: new Date() }), 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return <div className="text-blue-400">Time: {this.state.time.toLocaleTimeString()}div>;
}
}
Common Mistakes
- Not cleaning up resources in
componentWillUnmount. - Calling
setStateinrender.
Chapter 3: Handling Events
React handles events using camelCase and passes them as functions.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isOn: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({ isOn: !prevState.isOn }));
}
render() {
return (
<button className="bg-blue-500 text-white p-2 rounded" onClick={this.handleClick>
{this.state.isOn ? 'ON' : 'OFF'}
button>
);
}
}
Pro Tip
Use arrow functions in class fields to avoid binding event handlers in the constructor.
Module 3: Hooks and Functional Components
Chapter 1: useState Hook
Hooks allow functional components to use state and lifecycle features.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div className="p-4 text-blue-500">
<p>Count: {count}p>
<button className="bg-blue-500 text-white p-2 rounded" onClick={() => setCount(count + 1)>
Increment
button>
div>
);
}
Pro Tip
Use functional updates with setCount(prev => prev + 1) for state changes based on previous state.
Chapter 2: useEffect Hook
The useEffect Hook manages side effects in functional components.
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <div className="text-blue-400">Seconds: {seconds}div>;
}
Common Mistakes
- Missing dependency arrays in
useEffect, causing infinite loops. - Not returning a cleanup function for subscriptions.
Chapter 3: Custom Hooks
Custom Hooks extract reusable logic from components.
import React, { useState, useEffect } from 'react';
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return width;
}
function App() {
const width = useWindowWidth();
return <div className="text-blue-500">Window width: {width}div>;
}
Pro Tip
Prefix custom Hooks with use to indicate they follow Hook rules.
Module 4: React Router
Chapter 1: Basic Routing
React Router enables client-side navigation in React applications.
import { BrowserRouter, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav className="flex space-x-4 p-4">
<Link to="/" className="text-blue-500 hover:text-blue-300">HomeLink>
<Link to="/about" className="text-blue-500 hover:text-blue-300">AboutLink>
nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
BrowserRouter>
);
}
Pro Tip
Use exact on Route to prevent partial path matching.
Chapter 2: URL Parameters
URL parameters allow dynamic routing based on data.
import { useParams } from 'react-router-dom';
function UserProfile() {
const { id } = useParams();
return <div className="p-4 text-blue-500">User ID: {id}div>;
}
function App() {
return (
<BrowserRouter>
<Route path="/user/:id" component={UserProfile} />
BrowserRouter>
);
}
Common Mistakes
- Not using
useParamsto access URL parameters. - Using query strings instead of route parameters.
Chapter 3: Programmatic Navigation
Programmatic navigation allows redirecting users with JavaScript.
import { useHistory } from 'react-router-dom';
function LoginButton() {
const history = useHistory();
return (
<button className="bg-blue-500 text-white p-2 rounded" onClick={() => history.push('/login')>
Go to Login
button>
);
}
Pro Tip
Use useHistory for navigation in functional components.
Module 5: State Management with Context
Chapter 1: Context API Basics
The Context API allows sharing data without prop drilling.
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
ThemeContext.Provider>
);
}
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <div className={`p-4 text-${theme === 'light' ? 'black' : 'white'}`}>Theme: {theme}div>;
}
Pro Tip
Use Context for global data like themes or user authentication.
Chapter 2: Updating Context
Combine Context with state to allow updates.
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
ThemeContext.Provider>
);
}
function ThemeToggle() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button className="bg-blue-500 text-white p-2 rounded" onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')>
Toggle Theme
button>
);
}
Common Mistakes
- Overusing Context for all state management.
- Not memoizing context values to prevent re-renders.
Chapter 3: When to Use Context
Use Context for data that is global to many components.
- User authentication status
- Theme preferences
- Language settings
Pro Tip
Avoid Context for local state to keep components reusable.
Module 6: State Management with Redux
Chapter 1: Redux Basics
Redux is a predictable state container for JavaScript applications.
import { createStore } from 'redux';
const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
const store = createStore(reducer);
Pro Tip
Keep reducers pure and predictable for reliable state updates.
Chapter 2: React-Redux Integration
React-Redux connects Redux to React components.
import { Provider, useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return (
<div className="p-4">
<p className="text-blue-500">Count: {count}p>
<button className="bg-blue-500 text-white p-2 rounded mr-2" onClick={() => dispatch({ type: 'INCREMENT' })>+button>
<button className="bg-blue-500 text-white p-2 rounded" onClick={() => dispatch({ type: 'DECREMENT' })>-button>
div>
);
}
function App() {
return <Provider store={store}><Counter />Provider>;
}
Common Mistakes
- Not wrapping the app in
Provider. - Mutating state directly in reducers.
Chapter 3: Redux Toolkit
Redux Toolkit simplifies Redux setup and best practices.
import { configureStore, createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
increment(state) {
state.count += 1;
},
decrement(state) {
state.count -= 1;
}
}
});
export const { increment, decrement } = counterSlice.actions;
const store = configureStore({ reducer: counterSlice.reducer });
Pro Tip
Use Redux Toolkit’s createSlice to reduce boilerplate code.
Module 7: Advanced React Patterns
Chapter 1: Higher-Order Components
Higher-Order Components (HOCs) enhance components with additional functionality.
function withAuth(WrappedComponent) {
return function (props) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
return isAuthenticated ? (
<WrappedComponent {...props} />
) : (
<div className="text-red-500 p-4">Please log indiv>
);
};
}
const ProtectedPage = withAuth(function ({ name }) {
return <div className="text-blue-500">Welcome, {name}div>;
});
Pro Tip
Use HOCs to share logic across multiple components.
Chapter 2: Render Props
Render Props share code by passing a render function as a prop.
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = event => {
setPosition({ x: event.clientX, y: event.clientY });
};
return (
<div className="h-screen" onMouseMove=handleMouseMove>
{render(position)}
div>
);
}
function App() {
return (
<MouseTracker render={({ x, y }) => (
<p className="text-blue-500">Mouse: ({x}, {y})p>
)}/>
);
}
Common Mistakes
- Overcomplicating render prop logic.
- Not handling edge cases in render functions.
Chapter 3: Compound Components
Compound Components share state implicitly for cohesive UI.
function Tabs({ children }) {
const [activeIndex, setActiveIndex] = useState(0);
return React.Children.map(children, (child, index) => {
return React.cloneElement(child, {
isActive: index === activeIndex,
onSelect: () => setActiveIndex(index)
});
});
}
function Tab({ isActive, onSelect, children }) {
return (
<button className={`p-2 ${isActive ? 'bg-blue-500 text-white' : 'bg-gray-500 text-gray-300'}`} onClick=onSelect>
{children}
button>
);
}
function App() {
return (
<Tabs>
<Tab>Tab 1Tab>
<Tab>Tab 2Tab>
Tabs>
);
}
Pro Tip
Use React.cloneElement to pass props to children in Compound Components.
Module 8: Performance Optimization
Chapter 1: React.memo and useMemo
React.memo prevents unnecessary re-renders; useMemo memoizes values.
import React, { memo, useMemo } from 'react';
const Child = memo(function Child({ value }) {
return <div className="text-blue-500">Value: {value}div>;
});
function Parent({ a, b }) {
const expensiveResult = useMemo(() => {
return a * b;
}, [a, b]);
return <Child value=expensiveResult />;
}
Pro Tip
Use React.memo only when re-renders are costly.
Chapter 2: useCallback
useCallback memoizes callback functions to prevent re-creation.
import React, { useState, useCallback, memo } from 'react';
const Button = memo(function Button({ onClick }) {
return <button className="bg-blue-500 text-white p-2 rounded" onClick=onClick>Clickbutton>;
});
function App() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => setCount(prev => prev + 1), []);
return <Button onClick=handleClick />;
}
Common Mistakes
- Overusing
useCallback, adding unnecessary complexity. - Missing dependencies in the dependency array.
Chapter 3: Code Splitting
Code splitting reduces bundle size by loading components lazily.
import React, { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback=<div className="text-blue-500">Loading...div>
<LazyComponent />
Suspense>
);
}
Pro Tip
Combine React.lazy with Suspense for smooth loading states.
Module 9: Testing React Applications
Chapter 1: Jest Fundamentals
Jest is a JavaScript testing framework for unit and integration tests.
function sum(a, b) {
return a + b;
}
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Pro Tip
Use Jest’s snapshot testing for UI consistency checks.
Chapter 2: React Testing Library
React Testing Library tests components by simulating user interactions.
import { render, screen, fireEvent } from '@testing-library/react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}p>
<button onClick={() => setCount(count + 1)>Clickbutton>
div>
);
}
test('increments count', () => {
render(<Counter />);
fireEvent.click(screen.getByText('Click'));
expect(screen.getByText('1')).toBeInTheDocument();
});
Common Mistakes
- Testing implementation details instead of user behavior.
- Not waiting for async updates in tests.
Chapter 3: End-to-End Testing with Cypress
Cypress runs end-to-end tests in a browser environment.
describe('Counter App', () => {
it('increments count', () => {
cy.visit('/');
cy.contains('0');
cy.get('button').click();
cy.contains('1');
});
});
Pro Tip
Use Cypress for testing critical user flows across the app.
Module 10: Building and Deploying
Chapter 1: Create React App
Create React App sets up a modern React project with no configuration.
# Terminal commands
npx create-react-app my-app
cd my-app
npm start
Pro Tip
Use npm run build to create an optimized production build.
Chapter 2: Custom Webpack Configuration
Customize Webpack for advanced build requirements.
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react']
}
}
}
]
}
};
Common Mistakes
- Ejecting from Create React App prematurely.
- Misconfiguring Webpack loaders.
Chapter 3: Deployment Strategies
Deploy React apps to platforms like Netlify or Vercel.
# Deploy to Netlify
npm run build
netlify deploy --prod
# Deploy to Vercel
vercel --prod
Pro Tip
Configure server rewrites for single-page app routing.
React.js Career Paths
Complete all modules and pass the final test!