Handbooks / React / Chapter 1

Components and JSX

7 pages · ~4 min✓ Reviewed

Start here. Next up: State and Props.

ReactPage 1

Components and JSX Mental Model

1. What a Component Is

  • A function component takes props, returns JSX
  • Name starts with a capital, or <card /> is an HTML tag
  • UI = f(props, state): body is pure, no side effects

2. JSX Is Objects

  • JSX is sugar for jsx() calls returning plain element objects, not DOM nodes
jsx
const el = <h1 className="t">Hi</h1>;
// compiles to
const el = jsx("h1", { className: "t", children: "Hi" });

el is a plain object, not a DOM node

3. Props and Renders

  1. Props or state change
  2. Function re-called
  3. New element tree
  4. Diff, patch DOM
  • Each render is a fresh snapshot
  • Props are read-only: never mutate, pass new values down
Remember

Render only computes a description. React diffs it and touches the DOM only where it changed.

ReactPage 2

JSX Rules and Core Workflow

1. JSX Rules

  • One root: wrap siblings in a parent or a fragment <>...</>
  • Close every tag: <img />, <input />
  • {} embeds expressions (variable, call, ternary), not if or for
HTMLJSX
classclassName
forhtmlFor
onclick, tabindexonClick, tabIndex
style="color:red"style={{ color: 'red' }} (object)

2. Static vs Dynamic

WrittenKindPasses
name="Ada"statica string
size={40}dynamica number
{user.name}dynamicany expression

3. Core Workflow

  1. Definefunction Name
  2. Destructureprops in signature
  3. Return JSXone root
  4. Render<Name prop={value} />
jsx
function Avatar({ size, name }) {
  return <img width={size} alt={name} />;
}

// <Avatar size={40} name="Ada" />
Expressions only

No if or for inside {}: use a ternary or .map().

ReactPage 3

Lists, Keys and Conditional Rendering

1. Lists and Keys

  • key goes on the outermost element returned inside map
  • Keys are stable and unique among siblings
  • Use a database id, not Math.random()
  • Index key + reorder, insert or delete: state lands on the wrong row, because React matches by key
jsx
items.map(item => (
  <Row key={item.id} {...item} />
))

stable id as key

2. Conditional Rendering

PatternResult
c ? <A /> : <B />picks one of two
c && <A />A only when true
return nullrenders nothing
  • {count && <Badge />} renders 0 when count is 0
  • Fix: {count > 0 && <Badge />}

3. Early Return and Reset

  • Early return guards first, so the main JSX stays flat
jsx
if (!user) return <Login />;
return <Dashboard user={user} />;
Key resets state

Change a component's key and React remounts it, so its state resets: <Editor key={id} />

ReactPage 4

Composition, Children and Fragments

1. What children Is

  • children = special prop holding JSX nested between the tags
  • Composition beats inheritance: generic wrapper, content passed in
jsx
function Card({ children }) {
  return <div className="card">{children}</div>;
}
<Card>content</Card>

2. Named Slots

  • Slots are plain props that accept JSX
  • Nested content still arrives as children
jsx
<Layout header={<Nav />} sidebar={<Menu />}>
  main
</Layout>

3. Fragments

SyntaxUse
<>...</>Groups siblings, no DOM node, no key
<Fragment key={id}>Needs a key in a list

4. Lifting Content Up

Pass it through children

Avoids prop drilling. Passed-in elements are not re-rendered when the wrapper's state changes.

ReactPage 5

Common Mistakes

1. Component Mistakes

MistakeFixWhy it breaks
Component defined inside anotherMove it to module levelNew type each render: remount, state lost
<card /><Card />Lowercase is an HTML element
Card(props)<Card {...props} />Calling it directly breaks hooks

2. Lists and Render Mutation

  • Missing key, or key on the inner element: warning and bad diffing
  • Key goes on the element map returns
  • items.sort() in render mutates the array; copy first
jsx
// wrong: key on the inner element
items.map(i => <li><b key={i.id}>{i.name}</b></li>)
// right: key on the returned element
items.map(i => <li key={i.id}>{i.name}</li>)
// copy, then sort
[...items].sort(byName).map(/* ... */)

3. Interview Point

  • Why does an inner component lose state? New type every render, so React remounts it
  • Why not call Card(props)? No element, so hooks run in the parent
Remember

Capitalised, top-level, used as <Card />, keyed on the returned element, and copy before sort

ReactPage 6

Cheat Sheet

1. Component and JSX

  • Capital name, destructure props, return one root
  • Close every tag: <img />, <input />
  • className, htmlFor; {expr} for JS; style={{ color: 'red' }}
jsx
function Card({ title, children }) {
  return <div className="card">{children}</div>;
}

2. Lists and conditionals

  • key goes on the outer element in map: a stable unique id, not the index
jsx
items.map(x => <Item key={x.id} {...x} />)
NeedWrite
Either/orok ? <A /> : <B />
Show/hideok && <A /> (boolean only)
Nothingreturn null
Count checkn > 0 && <A />

3. Composition

  • children: <Wrapper>content</Wrapper>
  • Slot props: <Layout header={<Nav />}>main</Layout>
  • Fragment <>...</>: siblings, no wrapper node
The 0 trap

{count && <Badge />} renders 0 when count is 0.

ReactPage 7

Check yourself

count is 0. What does {count && <Badge />} put on the page?
  • It renders the number 0
  • && returns the falsy left side, and React prints numbers
  • Fix: count > 0 && <Badge />
Bug hunt: items.map(i => <li><Row key={i.id} /></li>) warns about keys. Why?
  • The key is on the inner Row, not on the li that map returns
  • Move it: <li key={i.id}>
Rows use key={index} and each holds a text input. You delete the first row, A. Whose typed text does the first row now show?
  • A's text, now beside B's label: key 0 survives and keeps its state
  • Use key={item.id} so A's state leaves with A