React View - Virtual DOM
React uses a Virtual DOM to efficiently update the UI.
Virtual DOM is a lightweight JavaScript representation of the real DOM. When a component's state changes, React:
-
Renders a new Virtual DOM tree.
-
Compares (diffs) it with the previous Virtual DOM tree.
-
Calculates the minimal set of changes needed.
-
Applies those changes to the real DOM.
Component Lifecycle
Most of us use Functional Components. Instead of multiple lifecycle methods, we use the useEffect Hook to handle all.
| Lifecycle Phase | Class Method | Functional Hook equivalent |
|---|---|---|
| Mounting | componentDidMount |
useEffect(() => { ... }, []) |
| Updating | componentDidUpdate |
useEffect(() => { ... }, [dependency]) |
| Unmounting | componentWillUnmount |
useEffect(() => { return () => { ... } }) |
More details:
| Class Component Method | Functional Hook Equivalent | When it runs |
|---|---|---|
constructor |
useState initializer or useMemo/useRef |
During render, before first paint |
getDerivedStateFromProps |
useState setter during render or useMemo |
During render, before first paint |
render |
The function body itself | Every render |
componentDidMount |
useEffect(fn, []) |
After first paint (commit phase) |
shouldComponentUpdate |
React.memo (for props), useMemo for values |
Before render, can skip re-rendering |
getSnapshotBeforeUpdate |
useLayoutEffect with previous values capture |
Just before DOM updates are applied |
componentDidUpdate |
useEffect(fn, [deps]) without cleanup |
After paint (if deps changed) |
componentWillUnmount |
Cleanup function of useEffect(fn, []) |
Before unmount |
componentDidCatch / getDerivedStateFromError |
No Hook equivalent (use a class error boundary) | When an error is thrown in a descendant |
React hooks
useState
-
Used to store and manage state in a functional component.
-
Returns an array of two items: the current state and a function to update it.
Example:
javascript
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0); // count starts at 0
const increment = () => {
setCount(count + 1); // update the state
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
Key points:
-
Calling
setCounttriggers a re-render. -
The state persists across renders.
useEffect
-
Used for side effects: things like fetching data, subscriptions, timers.
-
Runs after the component renders.
Basic usage:
javascript
import React, { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1); // update every second
}, 1000);
// Cleanup function
return () => clearInterval(interval);
}, []); // empty dependency array → runs only once
return <p>Seconds: {seconds}</p>;
}
export default Timer;
✅ Key points:
-
Dependency array (
[]) controls when the effect runs:-
[]→ once on mount. -
[count]→ runs whenevercountchanges. -
Omitted → runs after every render.
-
-
Can return a cleanup function to avoid memory leaks.
useState + useEffect together
They often pair to manage state reactively:
javascript
import React, { useState, useEffect } from "react";
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://api.example.com/data")
.then(res => res.json())
.then(json => setData(json));
}, []); // runs once on mount
if (!data) return <p>Loading...</p>;
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
export default DataFetcher;
Here's the flow:
-
Component mounts →
dataisnull. -
useEffecttriggers the fetch → updates state. -
setDatatriggers re-render, showing the fetched data.
Redux - State
Three core principles:
-
Single source of truth: The entire application state is stored in a single JavaScript object called the store.
-
State is read-only: The only way to change the state is to emit an action, an object describing what happened.
-
Changes are made with pure functions: To specify how the state tree is transformed by actions, you write reducers -- pure functions that take the previous state and an action, and return the next state.
What's Redux?
Use reducer to create/update/get store. Redux provides a predictable state container with a store, reducers, actions, and optional middleware for side effects.
Key concepts:
- Store
The core of Redux is "store".
Key functions: createStore(reducers[, initialState]), getState, dispatch, subscribe, etc.
The store is an object that holds the application state. It provides a few essential methods:
getState() -- returns the current state.
dispatch(action) -- sends an action to the reducer to trigger a state update.
subscribe(listener) -- registers a callback that will be called whenever the state changes.
- State
State is read-only, changes via pure functions (reducers).
- Reducer
A reducer is a function with the signature (state, action) => newState. It must be a pure function -- no side effects, no mutation of arguments. Given the same inputs, it must always return the same output.
Example of a simple reducer:
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
}
When your app grows, you can split reducers into smaller pieces and combine them with combineReducers:
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
counter: counterReducer,
user: userReducer,
// ...
});
combineReducers produces a single reducer that calls each child reducer and gathers their results into a single state object.
- Action
An action is a plain JavaScript object that must have a type property (usually a string constant) indicating the type of action being performed. It may also contain additional data (payload) needed to update the state. Store dispatch an action to update state.
const incrementAction = { type: 'INCREMENT' };
const addTodoAction = { type: 'ADD_TODO', payload: 'Learn Redux' };
Actions are created by action creators -- functions that return action objects:
function increment() {
return { type: 'INCREMENT' };
}
To update the state, you dispatch an action:
store.dispatch(increment());
- Middleware
Using middleware for async actions.
applyMiddleware, examples (redux-saga, redux-thunk).
Routing - React Router
Enables navigation between views.
AJAX request
fetch
Internationalization (i18n)
react-intj: a React library for internationalization (i18n),