Menu

4. React Fundamentals

Next.js Master Roadmap - IT Technology

This chapter introduces React fundamentals including JSX, components, props, state, and event handling, then dives into essential hooks like useState, useEffect, useContext, and custom hooks, providing practical examples and best practices.

No MCQ questions available for this chapter.

4. React Fundamentals

React Basics

4.1.1 What is React?

React is a declarative, component-based JavaScript library for building user interfaces. It minimizes direct DOM manipulations through a Virtual DOM diffing algorithm, ensuring efficient updates. Data flows in a unidirectional manner — from parent to child via props — making state changes predictable and easier to debug.

Example:

function App() { return <div><Header /><Main /><Footer /></div>; }

The above snippet composes the UI from reusable pieces: Header, Main, and Footer. Starting with React 18, concurrent features such as automatic batching and transitions improve responsiveness by allowing React to prepare multiple updates without blocking the main thread.

4.1.2 JSX

JSX (JavaScript XML) lets you write HTML‑like syntax directly in JavaScript. Under the hood, JSX is transpiled to React.createElement calls.

Basic syntax:

const element = <h1>Hello</h1>; // becomes React.createElement('h1', null, 'Hello')

Expressions are embedded using curly braces:

<div>{user.name}</div>

Fragments allow grouping without extra DOM nodes:

<><ChildA /><ChildB /></> or <React.Fragment><ChildA /><ChildB /></React.Fragment>

Dynamic attributes and event handlers:

<button className={isActive ? 'btn-active' : 'btn'} onClick={handleClick}>Click</button>

4.1.3 Components

Components are the building blocks of React UI. Function components are the preferred way due to their simplicity and compatibility with hooks.

Function component:

function Welcome({ name }) { return <h1>Hello, {name}</h1>; }

Class component (legacy):

class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }

Reusable button with defaults:

const Button = ({ children, onClick, variant = 'primary' }) => <button className={`btn btn-${variant}`} onClick={onClick}>{children}</button>;

4.1.4 Props

Props are read‑only inputs that flow from parent to child. They enable component composition and reuse.

  • Destructuring: function Card({ title, children })
  • Default props: Card.defaultProps = { title: 'Default' } or using default parameters.
  • Children prop: props.children lets a component receive arbitrary JSX.

Example with children:

<Modal title="Confirm" onClose={close}><p>Are you sure?</p></Modal>

Validation can be done with PropTypes or TypeScript interfaces to catch mistakes early.

4.1.5 State

Local component state is managed with the useState hook. State updates are asynchronous and may be batched for performance.

Basic usage:

const [count, setCount] = useState(0);

Functional updates ensure you work with the latest state:

setCount(c => c + 1);

Object state example:

const [form, setForm] = useState({ email: '', password: '' }); // Update while preserving other fields setForm(prev => ({ ...prev, email: 'new@email.com' }));

4.1.6 Event Handling

React uses SyntheticEvents that normalize browser differences. Handlers receive an event object; calling e.preventDefault() stops default browser actions.

Controlled input pattern:

<form onSubmit={e => { e.preventDefault(); submitForm(formData); }}> <input onChange={e => setValue(e.target.value)} /> </form>

React Hooks

4.2.1 useState

The useState hook returns a state variable and a setter function. Lazy initialization avoids expensive computations on every render.

Signature:

const [state, setState] = useState(initialValue);

Lazy initialization:

useState(() => expensiveComputation())

Example – persisting todos:

const [todos, setTodos] = useState<Todo[]>(() => { const saved = localStorage.getItem('todos'); return saved ? JSON.parse(saved) : []; });

4.2.2 useEffect

useEffect lets you perform side effects such as data fetching, subscriptions, or manual DOM changes. The cleanup function prevents memory leaks.

Signature:

useEffect(() => { ... }, [deps])
  • No dependency array → runs after every render.
  • Empty array → runs once on mount and cleanup on unmount.
  • Specific values → runs when any of those values change.

Subscription example:

useEffect(() => { const sub = api.subscribe(id, handleData); return () => sub.unsubscribe(); // cleanup }, [id]);

Document title side effect:

useEffect(() => { document.title = `Count: ${count}`; }, [count]);

4.2.3 useRef

useRef returns a mutable object whose .current property persists across renders without triggering re‑renders. It is commonly used to access DOM nodes or store previous values.

Signature:

const ref = useRef(initialValue);

Accessing an input:

const inputRef = useRef<HTMLInputElement>(null); const focus = () => inputRef.current?.focus(); <input ref={inputRef} />

Previous value pattern:

const prevCount = useRef(count); useEffect(() => { prevCount.current = count; });

4.2.4 useMemo

useMemo memoizes the result of an expensive calculation, recomputing only when its dependencies change. This prevents unnecessary work on every render.

Signature:

const memoized = useMemo(() => computeExpensive(a, b), [a, b]);

Example – sorted list:

const sortedUsers = useMemo(() => users.slice().sort((a, b) => a.name.localeCompare(b.name)), [users]);

Stable style object:

const style = useMemo(() => ({ width: `${progress}%` }), [progress]);

4.2.5 useCallback

useCallback returns a memoized version of a callback function that only changes when its dependencies change. This is useful when passing callbacks to memoized child components to prevent unnecessary re‑renders.

Signature:

const fn = useCallback(() => { doSomething(a); }, [a]);

Example – stable click handler for list items:

const handleClick = useCallback((id: string) => { analytics.track('click', { id }); navigate(`/item/${id}`); }, [navigate]);

Combine with React.memo on the child:

const ListItem = React.memo(({ id, onClick }) => <li onClick={() => onClick(id)}>Item {id}</li>);

4.2.6 useContext

useContext consumes a value from a React Context, causing the component to re‑render when the provider’s value changes. It eliminates prop drilling for global‑like data such as themes, authentication, or locale.

Signature:

const value = useContext(MyContext);

Example – thematic button:

const ThemeContext = createContext<Theme>('light'); function ThemedButton() { const theme = useContext(ThemeContext); return <button className={theme}>...</button>;}

4.2.7 Custom Hooks

Custom hooks allow you to extract reusable stateful logic into a function whose name starts with “use”. They can call other hooks and encapsulate side effects.

Example – useLocalStorage:

function useLocalStorage<T>(key, initial) { const [value, setValue] = useState(() => { const stored = localStorage.getItem(key); return stored ? JSON.parse(stored) : initial; }); useEffect(() => { localStorage.setItem(key, JSON.stringify(value)); }, [key, value]); return [value, setValue]; }

Example – useDebounce:

function useDebounce<T>(value: T, delay: number) { const [debounced, setDebounced] = useState(value); useEffect(() => { const t = setTimeout(() => setDebounced(value), delay); return () => clearTimeout(t); }, [value, delay]); return debounced; }

Component Architecture & Form Handling

Beyond the basics, scalable React applications benefit from a clear component hierarchy: presentational (UI‑only) vs. container (data‑fetching) components, or the newer approach of separating concerns with hooks and feature‑sliced design.

Form handling is streamlined with libraries like React Hook Form, which leverages uncontrolled inputs and minimizes re‑renders.

Basic React Hook Form usage:

import { useForm } from 'react-hook-form'; function Login() { const { register, handleSubmit, errors } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('email', { required: true, pattern: /^\S+@\S+$/i })} /> {errors.email && <span>Invalid email</span>} <input {...register('password', { required: true, minLength: 6 })} /> <button type="submit">Login</button> </form> ); }

Summary

This chapter covered the essential building blocks of React: JSX syntax, component creation, props and state management, event handling, and the powerful Hooks API. Mastery of these concepts enables developers to build efficient, maintainable, and scalable user interfaces, setting the foundation for advanced topics such as performance optimization, server‑side rendering with Next.js, and state management libraries.