Skip to main content

1.4 Modern ES6+ Syntax for React

← Back to Chapter 1: JavaScript Fundamentals

Modern JavaScript (ES6 and beyond) introduced syntax patterns and language operators that form the everyday vocabulary of modern React component authoring, state manipulation, conditional rendering, and module architecture.


1. Destructuring Assignment​

Destructuring allows unpacking values from arrays or properties from objects into distinct variables concisely.

Object Destructuring​

const user = {
id: 42,
username: "sarvy_dev",
profile: {
fullName: "Sarwvidya",
city: "Bangalore"
}
};

// Extraction, aliases (renaming), and fallback values
const {
username: handle,
profile: { fullName, city },
role = "Developer"
} = user;

console.log(handle); // "sarvy_dev"
console.log(fullName); // "Sarwvidya"
console.log(role); // "Developer" (used fallback default)

Array Destructuring​

Array destructuring unpacks values based on index position:

const coordinates = [12.9716, 77.5946, 920];

// Extracting with positional mapping and skipping elements
const [latitude, longitude, , altitude = 0] = coordinates;

// Swapping variables without a temporary variable
let a = 1, b = 2;
[a, b] = [b, a];
Destructuring in React

React's useState hook returns a two-element tuple [state, setState], making array destructuring the canonical way to consume it:

const [isOpen, setIsOpen] = useState(false);

Props in functional components are destructured directly in parameter lists:

function UserCard({ name, avatarUrl, badge = "PRO" }) {
return <div><h3>{name}</h3><span>{badge}</span></div>;
}

2. Spread (...) & Rest (...) Operators​

While both use three dots (...), their purposes are opposite:

  • Spread expands an iterable (array or object) into individual elements.
  • Rest condenses multiple individual elements into an array.

Spread for Immutability & Cloning​

// Copying & extending objects (Shallow copy)
const baseConfig = { theme: "dark", fontSize: 14 };
const customConfig = { ...baseConfig, fontSize: 16, lineNumbers: true };

// Concatenating arrays
const frontend = ["React", "CSS"];
const fullStack = [...frontend, "Node.js", "Java"];

Rest Parameter in Functions​

Rest parameters gather all remaining arguments into a true JavaScript array:

function calculateTotal(taxRate, ...prices) {
// prices is a real Array instance
const subtotal = prices.reduce((acc, curr) => acc + curr, 0);
return subtotal * (1 + taxRate);
}

console.log(calculateTotal(0.08, 20, 50, 30)); // 108
Shallow Copy Warning

The spread operator only creates a shallow copy. If an object contains nested objects or arrays, references to those nested structures are preserved:

const original = { details: { theme: 'dark' } };
const copy = { ...original };
copy.details.theme = 'light';
console.log(original.details.theme); // 'light' (mutated!)

3. Default Parameters​

Default parameters allow formal function parameters to be initialized with default values if no value or undefined is passed during invocation.

function createButton(label = "Click Me", theme = "primary", size = "medium") {
return `<button class="${theme} ${size}">${label}</button>`;
}

console.log(createButton()); // <button class="primary medium">Click Me</button>
console.log(createButton("Save", "success")); // <button class="success medium">Save</button>

Key Behaviors:​

  1. Triggered ONLY by undefined: Passing null, false, 0, or "" will not trigger the default value!
    function greet(name = "Anonymous") {
    return `Hello, ${name}!`;
    }
    console.log(greet(undefined)); // "Hello, Anonymous!"
    console.log(greet(null)); // "Hello, null!"
  2. Evaluated at Call Time: Defaults are evaluated on each invocation, not when the function is defined:
    function createId(id = Math.random().toString(36).substring(2, 9)) {
    return id;
    }
    // Each call generates a unique id if not provided
  3. Earlier Parameters Accessible: Later default parameters can reference earlier parameters in the list:
    function computeTax(price, taxRate = 0.05, total = price * (1 + taxRate)) {
    return total;
    }

4. The Ternary Operator (condition ? trueExpr : falseExpr)​

The ternary operator is JavaScript's only three-operand operator, providing an inline expression alternative to if...else statements.

const userRole = "admin";
const accessLevel = userRole === "admin" ? "Full Access" : "Read-Only";

Conditional Rendering in React JSX​

Unlike if...else statements (which are statements and cannot be embedded directly inside JSX expressions {}), the ternary operator is an expression that returns a value:

function AuthHeader({ isLoggedIn, user, onLogout, onLogin }) {
return (
<header className="navbar">
<h1>Dashboard</h1>
{isLoggedIn ? (
<div className="user-menu">
<span>Welcome, {user.name}</span>
<button onClick={onLogout}>Sign Out</button>
</div>
) : (
<button onClick={onLogin} className="btn-primary">
Sign In
</button>
)}
</header>
);
}
Avoiding Ternary Hell

Avoid chaining multiple nested ternaries. When dealing with 3 or more states, use guard clauses, helper functions, or lookup objects:

// ❌ Hard to read / nested ternary:
const statusText = isSuccess ? "Done" : isLoading ? "Loading..." : isError ? "Failed" : "Idle";

// ✅ Clean lookup dictionary:
const STATUS_LABELS = {
idle: "Idle",
loading: "Loading...",
success: "Done",
error: "Failed"
};
const statusText = STATUS_LABELS[status];

5. Optional Chaining (?.) & Nullish Coalescing (??)​

Optional Chaining (?.)​

Prevents runtime TypeError: Cannot read properties of undefined/null by short-circuiting to undefined if a reference is nullish:

const apiResponse = { user: null };

// Safe property navigation
const street = apiResponse.user?.address?.street; // undefined (no crash)

// Safe method execution
apiResponse.user?.logActivity?.();

// Safe dynamic bracket access
const firstItem = apiResponse.items?.[0];

Nullish Coalescing (??) vs Logical OR (||)​

  • || returns the right-hand operand if the left operand is any falsy value (false, 0, "", null, undefined, NaN).
  • ?? returns the right-hand operand only if the left operand is null or undefined.
const animationDuration = 0;

const timeoutOr = animationDuration || 300; // 300 (Bug! 0 is a valid duration)
const timeoutNullish = animationDuration ?? 300; // 0 (Correct!)

6. Template Literals & Tagged Templates​

Template literals use backticks (`) and support string interpolation, expressions, and multiline formatting:

const framework = "React";
const version = 19;
const message = `Learning ${framework} version ${version}. Multi-line strings
work without manual \\n escape characters.`;

Tagged Templates​

Tagged templates allow parsing template literals with a function. This is the underlying engine powering CSS-in-JS libraries like styled-components:

function highlight(strings, ...values) {
return strings.reduce((acc, str, i) => {
return `${acc}${str}<strong>${values[i] ?? ''}</strong>`;
}, '');
}

const topic = "Hooks";
const result = highlight`Mastering React ${topic} is fun!`;
// "Mastering React <strong>Hooks</strong> is fun!<strong></strong>"

7. ES Modules (ESM) — import & export​

Modern JavaScript organizes code into standardized modules using import and export.

// mathUtils.js - Named & Default exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default class Calculator { /* ... */ }

// App.js - Importing
import Calculator, { PI, add as sum } from './mathUtils.js';

Dynamic Imports & React Code Splitting​

Dynamic imports load modules on-demand, reducing initial bundle size:

// Dynamic import returns a Promise
import('./analytics.js').then(module => {
module.initAnalytics();
});
// In React: Code splitting routes with React.lazy
import React, { lazy, Suspense } from 'react';

const AdminDashboard = lazy(() => import('./AdminDashboard.jsx'));

function App() {
return (
<Suspense fallback={<p>Loading Admin module...</p>}>
<AdminDashboard />
</Suspense>
);
}

8. Summary Checklist​

  • Destructure objects and arrays to write clean, declarative component props and state.
  • Use spread for shallow immutability; recognize that nested structures need recursive copying.
  • Use default parameters to provide sensible fallbacks when arguments are undefined.
  • Use ternary operators for inline conditional rendering in React JSX.
  • Use ?. to guard nested property chains and ?? when 0 or "" are legitimate values.
  • Structure applications into reusable ES Modules with named and default export/import.