React
The benefit of React is that it only updates DOM elements that have changed by managing a virtual DOM. It also allow us to swap component out of webpages.
Primary Libraries :
import React from 'react': for pure React purposes; the library does not interact with the DOM; mainly use for creating components or writing JSX elementsimport ReactDOM from 'react-dom/client': contains methods for React to interact with DOM
JSX
JSX is the language use for React. It's a combination of Javascript + HTML. JSX is used everywhere between the opening and closing tags of JSX elements
JSX Elements
- JSX Elements are the same as HTML Elements, like
div button input pexcept they're in Javascript file, but they are not the same as React components - They can contain attributes like
id - The HTML attribute
classcan not be used in JSX, insteadclassNamehas to be used instead because class is a reserved Javascript keyword - They can be assigned to variables and pass around like functions
- They must be wrapped in parenthesis () if the element require multiple lines of code
- There can only be one outermost html element in a jsx element
Differences in React :
- The HTML attribute
classcan not be used in JSX, insteadclassNamehas to be used instead because class is a reserved Javascript keyword - Elements that have a self-closing tag MUST have a forward slash before the final bracket
- Example:
<img src=""/> <input name=""/> <br/> - JSX elements must be wrapped in parenthesis () if the element require multiple lines of code
- Similar to injecting Javascript
${expression}in string, it's possible to inject Javascript into JSX expressions too, but using only curly braces{js expression} - Example:
<img src={variableName}/>: there is no need for quotation mark
const jsxElement = (
<div className="top-bar">
<div className="top-nav">
<button id="menuBtn" onClick={functionName}>Menu</button>
<a href="#">Link</a>
</div>
</div>
);Rendering JSX Elements
- JSX element typically render to one react root.
- Use
createRoot()method to create the root from 'react-dom/client' library - Use
render()method to render the JSX element
import React from 'react';
import ReactDOM from 'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(jsxElement);
// HTML
<div id="root"></div>Conditional Rendering
- You can use the ternary operator and
&&to make conditional rendering, but notifstatements
// Using ternary operator
const headline = (
<h1>
{ age >= drinkingAge ? 'Buy Drink' : 'Do Teen Stuff' }
</h1>
);
// Using && operator
const tasty = (
<ul>
<li>Applesauce</li>
{ !baby && <li>Pizza</li> }
</ul>
);Using array.map() Method
The map() method is very useful for building repetitive elements from an array.
// Mapping a string array
const strings = ['Home', 'Shop', 'About Me'];
const listItems = strings.map(string => <li key="string">{string}</li>);
root.render(<ul>{listItems}</ul>);
// Output
<ul>
<li key="Home">Home</li>
<li key="Shop">Shop</li>
<li key="About Me">About Me</li>
</ul>// Mapping a set
const navSet = {
'Home': '/index.html',
'Shop': '/shop.html',
'About Me': '/aboutMe.html'
};
const navMenu = Object.keys(navSet).map(([name, url]) => <a key={name} href={url}>{name}</a>);
root.render(navMenu);
// Output:
<a key="Home" href="/index.html">Home</a>,
<a key="Shop" href="/shop.html">Shop</a>,
<a key="About Me" href="/aboutMe.html">About Me</a>JSX key Attribute
When rendering with map(), React uses the key attribute to identify which element was mapped from which value. This allows React to update/remove only the necessary element when the list changes.
keymust be unique among siblings element, but they don't have to be globally unique- Don't use the array index as a key unless you're sure items never reorder or get removed.
- Combining value and index to make a key can work, but list can not be re-ordered:
key={array[i] + i} - Keys are not accessible inside the component via
props - ALWAYS try to have the key attribute for repetitive elements as it makes rendering more efficient
React Component
- Component: for React, it is a block of code that renders HTML and re-renders whenever some data changes
- Functional Component: a JavaScript function that returns a JSX element (a component)
- Functional components MUST begin with a capital letter, or the React compiler will not recognize it as a React component
- The JS file of the component should also have the first letter capitalized for easy recognition.
- They can be used like JSX elements: nesting other components and adding attributes, but require passing and using
propswithin the function
// MySimpleComponent cannot accept attributes or have nested children
function MySimpleComponent() {
return <div>Hello, I'm a functional React Component!</div>;
}
// MyNewComponent can accept attributes and nested children because it uses props
function MyNewComponent(props) {
return (
<div className={props.className}> {props.children || "Hello, I'm a functional React Component!"}</div>
);
}
// Using functional component
const nestedComponent = (
<MyNewComponent className="top-bar">
<OtherComponent />
</MyNewComponent>
);
// Rendering functional component
root.render(<MySimpleComponent />)Functional Component (with Hooks) Lifecycle
Sequence: Mount → Render → Update (re-render on state/props change) → Unmount
- Mounting:
- Runs the function once
useEffect(() => {... }, [])runs after the initial render
- Updating:
- Function runs again when state or props change
useEffect(() => {... })runs after every render by defaultuseEffect(() => {... }, [deps])runs when dependencies change
- Unmounting:
- Cleanup function inside
useEffectruns
- Cleanup function inside
Props
props are used to pass information from one component to another (like className, style, children nodes)
- The functional component adds
propsinto its argument to indicate it will accept attributes - By giving attributes to the component, the attributes and their values are passed to the functional component via
props - Add curly braces
to pass JavaScript expressions like functions, arrays, or objects - Use
useContextif you're passingpropsdeeply or need shared state across multiple components
// Passing info to Button component as attributes
root.render(
<Button className="submitBtn" onClick={myFunction} data={[1, 2, 3]} />
);
// The functional component accesses the info using props
function Button(props) {
calcData(props.data);
return <button className={props.className} onClick={props.onClick} />;
}
// Using destructuring to simplify
function Button({ data, className, onClick }) {
calcData(data);
return <button className={className} onClick={onClick} />;
}Passing Props to Children Components
props are immutable (read-only) and one-way: data flows down from the parent to the child
- If a child component needs to modify a prop, the parent must pass a callback function as a reference
// Parent component
function Parent() {
const [count, setCount] = React.useState(0);
// handleIncrement allows the child component to modify the count
const handleIncrement = () => {
setCount(current => current + 1);
};
return <Child count={count} onIncrement={handleIncrement} />;
}
// Child component
function Child({ count, onIncrement }) {
count = count + 1; // ❌ this won't work; props are read-only
return (
<div>
<p>Count: {count}</p>
<button onClick={onIncrement}>Increment</button>
</div>
);
}
----------------------------------------------------------------
// Simplified version using setCount directly
function Parent() {
const [count, setCount] = React.useState(0);
return <Child count={count} setCount={setCount} />;
}
function Child({ count, setCount }) {
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(current => current + 1)}>Increment</button>
</div>
);
}Nesting Components with props.children
props.children returns everything between a component's opening and closing JSX tags
- Useful for reusing components while letting the parent control the content
// Parent component
function Grid() {
return (
<grid>
<Card>
<h5>Image 1</h5>
<img src="/image1.jpg" />
</Card>
<Card>
<h5>Image 2</h5>
<img src="/image2.jpg" />
</Card>
</grid>
);
}
// Child component
// Content inside Card depends on parent; makes lower-level components reusable
function Card(props) {
return (
<div className="grid-item">
{props.children}
</div>
);
}Setting Default Values for props
Default values can be set for props if none are passed, using three methods:
- Add a
defaultPropsstatic property
function Card({ src = '/defaultImage.jpg' }) {
return <img src={src} />;
}
Card.defaultProps = {
src: '/defaultImage.jpg',
};function Card({ src = '/defaultImage.jpg' }) {
return <img src={src} />;
}function Card(props) {
const { src = '/defaultImage.jpg' } = props;
return <img src={src} />;
}Suspense API and use Hook
The Suspense component in React lets you handle many nested async operations cleanly. Until the async functions finish, the component will show a subsitute using the attribute fallback
- Primarily used with the
usehook to tell when the async functions are finished - While in the suspended state (i.e. not finished/still loading), the children elements are not rendered yet
- It stays suspended until all nested async functions are finished
- Documentation: react.dev/reference/react/Suspense
The use Hook
resolvedValue = use( Promise )
- As of React 18+, the hook only accepts cached Promise or Promises that came from a Server component
- Documentation: react.dev/reference/react/use
- Notes on Promises in javascript: link
import { Suspense } from 'react';
export default function MyPage(){
return (
<Suspense key={index} fallback={<div>Loading...</div>}>
<LazyImage src={src} className={styles.img} />
</Suspense>
);
}
---------------------------------------------------------------
// Using cached Promises with Suspense
'use client';
import React, { use } from 'react';
const imgCache = new Map();
function loadImage(src) {
if (!imgCache.has(src)) {
imgCache.set(
src,
new Promise((resolve, reject) => {
const img = new window.Image();
img.src = src;
img.onload = resolve;
img.onerror = reject;
})
);
}
return imgCache.get(src);
}
export default function LazyImage({ className, src }) {
use(loadImage(src));
return <img src={src} className={className}/>
}Event Listener & Handler
Event handlers are custom callback functions with the naming convention that they start with 'handle'
Event listeners are used in the same way as their HTML counterpart
Naming Convention
- React uses camelCase to name their events -
onClickinstead ofclick - The custom callback function that handles the event commonly starts with 'handle'
- For 'click' event, the callback function would be named
handleClick - For 'hover' event, the callback function would be named
handleHover
// JSX
function SubmitButton() {
function handleClick() {
alert('Submission Successful.');
}
return <button onClick={handleClick}>Submit</button>;
}Common Event React Supports
- Mouse Events
onClick: Mouse click on an elementonDoubleClick: Double-click on an elementonMouseDown/onMouseUp: Mouse button pressed/releasedonMouseMove: Mouse moves over an elementonMouseEnter/onMouseLeave: Mouse enters/leaves (no bubbling)onMouseOver/onMouseOut: Mouse enters/leaves (bubbles)onContextMenu: Right-click context menu
- Pointer Events
onPointerDown,onPointerUp,onPointerMove: Pointer pressed, released, movedonPointerEnter,onPointerLeave: Pointer enters/leaves (no bubbling)onPointerOver,onPointerOut: Pointer enters/leaves (bubbles)onPointerCancel: Pointer interaction canceled
- Keyboard Events
onKeyDown: Key is pressed downonKeyPress: Key is pressed (deprecated, preferonKeyDown)onKeyUp: Key is released
- Form & Input Events
onSubmit: Form submissiononChange: Input/select value changesonInput: Input value changes (real-time)onFocus/onBlur: Element gains or loses focusonInvalid: Form validation failsonReset: Form reset
- Clipboard Events
onCopy,onCut,onPaste: Clipboard interactions
- Drag & Drop Events
onDragStart,onDrag,onDragEnd: Drag starts, moves, endsonDragEnter,onDragOver,onDragLeave,onDrop: Drag target interactions
- Touch Events
onTouchStart,onTouchMove,onTouchEnd,onTouchCancel: Touch interactions
- Composition Events
onCompositionStart,onCompositionUpdate,onCompositionEnd: IME text input handling
- Media Events
onPlay,onPause,onEnded: Media playback stateonVolumeChange,onTimeUpdate,onProgress: Media volume, time, and loading progressonLoadedData,onLoadedMetadata,onCanPlay,onCanPlayThrough: Media readiness eventsonStalled,onSuspend,onWaiting: Media buffering states
- Animation & Transition Events
onAnimationStart,onAnimationEnd,onAnimationIteration: CSS animationsonTransitionEnd: CSS transition ends
- Wheel & Scroll Events
onWheel: Mouse wheel scrollonScroll: Scroll event on an element
More events: react.dev/reference/react-dom/components/common
Communicating Between Components
- Using
props: parent to children - Using
ref: parent → child 1 → parent → child 2 - Using
context: as long as the components are wrapped around the context provider - Using
zustand store: global