In a Single-Page Application (SPA) — a web application that runs on a single HTML page — a Component-Based Architecture is essential for organizing different sections and layouts efficiently.
React enables this by providing a declarative, reusable, and scalable component model that simplifies UI development.
[!info] npm Commands
npm init— initialize a new Node.js projectnpm i— install dependenciesnpm i <package>— install a specific packagenpm run <script>— run a script from package.json
Create React App (CRA)
npx create-react-app <appName>
Slower because it includes full bundling and tooling.
Vite
npm create vite@latest <appName>
Faster — uses a modern build tool with optimized dev server.
| File | Purpose |
|---|---|
| index.html | Single HTML page of the SPA |
| package.json | Project metadata, dependencies, and scripts |
| vite.config.js | Vite build configuration |
| /src | Main source folder for React code |
| main.jsx | Entry point, connects React to HTML |
| App.jsx | Root React component |
| App.css | CSS specific to App.jsx |
| index.css | Global CSS for the entire app |
index.html
↓
main.jsx → connects React to the HTML page
↓
<App.jsx> → root component rendered inside #root
↓
App.css → component-specific styles
index.css → global styles
<> </> fragments for grouping{} for dynamic expressionsclassName, onClick, onChangeReact uses a Virtual DOM and Reconciliation.
[!info] Features
- Must include a
render()method- Can maintain state
- Can receive props
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Props are data passed from a parent to a child component.
this.props.propNameprops as argumentsuper(props)When dealing with this, the binding context matters.
| Method | Example | Notes |
|---|---|---|
| Constructor binding | this.handleClick = this.handleClick.bind(this) |
Best performance |
| Arrow class property | handleClick = () => {...} |
Easiest to write |
| Inline arrow | onClick={() => this.handleClick()} |
OK for small use cases |
this.state = { value: 0 };
this.setState({ value: 1 });
this.setState(prev => ({ value: prev.value + 1 }));
React class components follow this flow:
constructor() → render() → componentDidMount() →
componentDidUpdate() → componentWillUnmount()
constructor() → initialize state, bind methodsrender() → return JSXcomponentDidMount() → run side effectsshouldComponentUpdate() → control re-renderrender()componentDidUpdate()componentWillUnmount() → cleanupFunctional components are simple JavaScript functions that:
[!info] Features
- Start with a capitalized name
- Return JSX
- Are simpler than class components
- Use Hooks for state & side effects
Example code:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
Hooks enable: State, Side effects, Context, Reusable logic (custom hooks)
const [state, setState] = useState(initialValue);
setState(prev => prev + 1);
setUser(prev => ({ ...prev, name: "Jason" }));
Manages side effects: fetching, subscriptions, logging.
| Dependency | Behavior |
|---|---|
| none | Runs after every render |
[] |
Runs once on mount |
[value] |
Runs when value changes |
Cleanup: Executed before re-running the effect:
const [state, dispatch] = useReducer(reducer, initialState);
function reducer(state, action) {
return newState;
}
Rules:
{ type: "increment" }
{ type: "add_todo", payload: "Buy milk" }
const countRef = useRef(0);
countRef.current++;
const sortedList = useMemo(() => sort(list), [list]);
const handleClick = useCallback(() => setCount(c => c + 1), []);
const Child = React.memo(function Child({ value }) {
return <div>{value}</div>;
});
const About = React.lazy(() => import('./About'));
<Suspense fallback={<p>Loading...</p>}>
<About />
</Suspense>
<input ref={inputRef} />
<input value={email} onChange={e => setEmail(e.target.value)} />