React ES6 Destructuring

Destructuring unpacks values from objects and arrays into individual variables, and it's the standard way React reads props.

Object destructuring

Object destructuring pulls named properties off an object into local variables in a single statement, matching by property name rather than position. You can rename variables, provide default values for missing properties, and destructure nested objects in one expression.

Object destructuring basics

export default function App() {
  const user = { id: 7, name: 'Priya', role: 'admin' };

  const { name, role } = user;
  console.log(name, role); // "Priya" "admin"

  // Renaming while destructuring
  const { name: displayName } = user;
  console.log(displayName); // "Priya"

  // Default value for a missing property
  const { theme = 'light' } = user;
  console.log(theme); // "light" (not present on `user`, so default is used)

  return (
    <div>
      <p>name: {name}</p>
      <p>role: {role}</p>
      <p>displayName: {displayName}</p>
      <p>theme: {theme}</p>
      <p>Open the console to see the logged values.</p>
    </div>
  );
}

Array destructuring

Array destructuring unpacks by position instead of name, which is exactly why useState's return value — a two-element array of [value, setter] — is destructured rather than accessed by index.

Array destructuring, including useState

import { useState } from 'react';

const coordinates = [12.5, 47.9];
const [lat, lng] = coordinates;
console.log(lat, lng); // 12.5 47.9

// Skipping elements with commas
const [first, , third] = ['a', 'b', 'c'];
console.log(first, third); // "a" "c"

// The pattern behind useState
function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

export default function App() {
  return (
    <div>
      <p>lat: {lat}, lng: {lng}</p>
      <p>first: {first}, third: {third}</p>
      <Counter />
      <p>Open the console to see the logged values.</p>
    </div>
  );
}

Destructuring props

React components receive a single 'props' object as their argument. Destructuring it directly in the function signature is the idiomatic way to declare which props a component expects, and it doubles as lightweight documentation.

Destructuring props in a function signature

// Without destructuring — has to repeat `props.` everywhere
function UserCard(props) {
  return <h2>{props.name} ({props.role})</h2>;
}

// With destructuring, including a default value and renaming
function UserCardBetter({ name, role = 'member', id: userId }) {
  return (
    <h2 data-user-id={userId}>
      {name} ({role})
    </h2>
  );
}

export default function App() {
  return (
    <div>
      <UserCard name="Priya" role="admin" />
      <UserCardBetter name="Sam" id={42} />
    </div>
  );
}

Destructuring also works with nested structures and the rest pattern, which collects the remaining properties or elements that weren't explicitly pulled out. This is common when a component needs a few specific props but should forward everything else to an underlying DOM element.

Nested destructuring and the rest pattern

function Avatar({ user: { name, imageUrl }, size = 'medium', ...rest }) {
  return (
    <img
      src={imageUrl}
      alt={name}
      className={`avatar avatar--${size}`}
      {...rest}
    />
  );
}

export default function App() {
  // Usage: extra props like onClick flow through via {...rest}
  return (
    <Avatar user={{ name: 'Sam', imageUrl: '/sam.png' }} onClick={() => {}} />
  );
}
  • Object destructuring matches by property name; array destructuring matches by position.
  • Default values only apply when the value is 'undefined', not for null or 0.
  • The rest pattern (...rest) must come last and collects everything not already destructured.
  • Destructuring in a function parameter list destructures the argument as soon as the function is called.
SyntaxUnpacks byCommon React use
const { a, b } = objProperty nameReading props, context values
const [a, b] = arrIndex positionuseState, useReducer results
const { a: renamed } = objName, then renameAvoiding naming collisions
const { a, ...rest } = objName, then gather remainderForwarding unused props to DOM
Note: Destructuring an object that is 'null' or 'undefined' throws a TypeError, since there's nothing to read properties from. When destructuring a prop that might be missing, destructure with a default at the top level, e.g. `function Panel({ items = [] })`, rather than only defaulting inner fields.
Note: `const { name: displayName } = user;` creates a variable called 'displayName', not 'name' — the colon means 'rename to', which is the opposite of what object literal shorthand `{ name }` does. Mixing these up is a common source of 'x is not defined' errors.

Exercise: React ES6 Destructuring

What does writing `function Welcome({ name, age })` do with the incoming props object?