React Cheatsheet

Lists and Keys

Use this React reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Rendering Lists with map

// Basic list rendering
function NameList({ names }) {
  return (
    <ul>
      {names.map((name, index) => (
        <li key={index}>{name}</li>
      ))}
    </ul>
  );
}

// Objects — use stable ID as key
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          <strong>{user.name}</strong> — {user.email}
        </li>
      ))}
    </ul>
  );
}

Keys

A key is a special string attribute that helps React identify which items have changed, been added, or removed.

// key must be:
// 1. Unique among siblings (not globally)
// 2. Stable across renders (not random)
// 3. Predictable from the data

// GOOD — stable ID from data
{items.map(item => <Item key={item.id} data={item} />)}

// ACCEPTABLE — stable string key
{Object.entries(config).map(([key, val]) => (
  <ConfigRow key={key} name={key} value={val} />
))}

// BAD — index as key when list can reorder/filter/insert
{items.map((item, i) => <Item key={i} />)} // causes bugs with state

// OK to use index only when:
// - list is static and never reorders
// - items have no state or controlled inputs
{staticLabels.map((label, i) => <span key={i}>{label}</span>)}

// BAD — random key causes remount every render
{items.map(item => <Item key={Math.random()} />)}

Key Rules and Gotchas

// Keys must be unique among SIBLINGS only, not across the whole tree
function App() {
  return (
    <>
      <ul>
        {listA.map(i => <li key={i.id}>{i.name}</li>)} {/* keys scoped here */}
      </ul>
      <ul>
        {listB.map(i => <li key={i.id}>{i.name}</li>)} {/* separate scope */}
      </ul>
    </>
  );
}

// Key is NOT accessible as a prop — use a separate id prop if needed
function Item({ id, data }) {    // key={id} above; pass id separately
  // props.key → undefined
}

// Keys on Fragments
import { Fragment } from 'react';
{items.map(item => (
  <Fragment key={item.id}>
    <dt>{item.term}</dt>
    <dd>{item.def}</dd>
  </Fragment>
))}
// Shorthand <> </> does NOT accept key — must use <Fragment>

List Transformations

// filter then map
{users
  .filter(u => u.active)
  .map(u => <UserCard key={u.id} user={u} />)
}

// sort then map (sort mutates — copy first)
{[...items]
  .sort((a, b) => a.name.localeCompare(b.name))
  .map(item => <li key={item.id}>{item.name}</li>)
}

// flatMap
{sections
  .flatMap(section => section.items)
  .map(item => <li key={item.id}>{item.title}</li>)
}

// reduce to group, then render groups
const byCategory = items.reduce((acc, item) => {
  (acc[item.category] ??= []).push(item);
  return acc;
}, {});

{Object.entries(byCategory).map(([cat, items]) => (
  <div key={cat}>
    <h3>{cat}</h3>
    <ul>{items.map(i => <li key={i.id}>{i.name}</li>)}</ul>
  </div>
))}

Nested Lists

function Tree({ nodes }) {
  return (
    <ul>
      {nodes.map(node => (
        <li key={node.id}>
          {node.label}
          {node.children?.length > 0 && <Tree nodes={node.children} />}
        </li>
      ))}
    </ul>
  );
}

Keyed Fragments and Tables

// Table rows
function Table({ rows }) {
  return (
    <table>
      <tbody>
        {rows.map(row => (
          <tr key={row.id}>
            {row.cells.map((cell, i) => <td key={i}>{cell}</td>)}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

// Definition list with keyed fragments
function Glossary({ terms }) {
  return (
    <dl>
      {terms.map(({ id, word, def }) => (
        <Fragment key={id}>
          <dt>{word}</dt>
          <dd>{def}</dd>
        </Fragment>
      ))}
    </dl>
  );
}

Empty States

function ItemList({ items }) {
  if (!items.length) return <p className="muted">No items found.</p>;

  return <ul>{items.map(i => <li key={i.id}>{i.name}</li>)}</ul>;
}

// Inline empty state
{items.length === 0
  ? <p>Nothing here yet.</p>
  : <ul>{items.map(...)}</ul>
}

Virtualization (Large Lists)

For thousands of items, virtualize to only render visible rows.

// react-window
import { FixedSizeList } from 'react-window';

function VirtualList({ items }) {
  const Row = ({ index, style }) => (
    <div style={style}>{items[index].name}</div>
  );

  return (
    <FixedSizeList
      height={600}
      itemCount={items.length}
      itemSize={48}
      width="100%"
    >
      {Row}
    </FixedSizeList>
  );
}

// react-virtual (TanStack Virtual) — headless alternative
import { useVirtualizer } from '@tanstack/react-virtual';

Generating Unique Keys

// When data has no ID, generate one at creation time (not in render)
import { useId } from 'react'; // for DOM ids only
import { nanoid } from 'nanoid'; // npm install nanoid

// Add ID when adding to state — NOT inside map()
const addItem = (text) =>
  setItems(prev => [...prev, { id: nanoid(), text }]);

// crypto.randomUUID() — native, available in modern browsers/Node
const id = crypto.randomUUID();

Performance Tips

// 1. Keys enable minimal DOM updates — correct keys > everything else

// 2. Memoize expensive list items
const MemoItem = React.memo(Item);
{items.map(i => <MemoItem key={i.id} data={i} />)}

// 3. Stable callbacks to memoized children (use useCallback)
const handleDelete = useCallback((id) => {
  setItems(prev => prev.filter(i => i.id !== id));
}, []);

// 4. Avoid inline arrow functions in map when children are memoized
// BAD: <Item key={i.id} onDelete={() => deleteItem(i.id)} />  — new fn each render
// GOOD: pass stable handler + id; let Item call it