Skip to content

Lists, keys, and conditionals without directives ​

Vue gave you v-if / v-for. React gives you JavaScript. Same problems, fewer magic attributes.

Conditionals ​

tsx
function Inbox({ messages }: { messages: Message[] }) {
  if (messages.length === 0) {
    return <p>Inbox zero. Nice.</p>
  }

  return (
    <ul>
      {messages.map((m) => (
        <li key={m.id}>{m.subject}</li>
      ))}
    </ul>
  )
}

Ternary inline when it's small:

tsx
{isOpen ? <Dropdown /> : null}

Keys - same rules as Vue, same pain when ignored ​

tsx
{items.map((item) => (
  <Row key={item.id} item={item} />
))}

Comments for the code above:

  • key helps React match instances across re-renders
  • Stable IDs > array index (index is OK for static lists that never reorder)
  • Changing a key remounts the component - useful trick to reset state

Remount with key (underrated) ​

Vue folks sometimes use :key on a component to force reset. Same in React:

tsx
<UserEditor key={userId} userId={userId} />

When userId changes, React throws away the old tree and mounts fresh. Local form state resets. Cleaner than a pile of useEffect sync code.

Filtering / sorting ​

Do it in JS before JSX - don't invent template filters:

tsx
const visible = todos.filter((t) => (showDone ? true : !t.done))

return (
  <ul>
    {visible.map((t) => (
      <li key={t.id}>{t.text}</li>
    ))}
  </ul>
)

As you can see - prepare data, then render. Keeps JSX readable.

Empty states and loading ​

I like early returns for the "not ready" branches:

tsx
if (isLoading) return <Spinner />
if (error) return <ErrorMessage error={error} />
if (!data) return null
return <Results data={data} />

Reads top-to-bottom. Nested ternaries in JSX get ugly fast.

Next: forms - controlled inputs, the React default.

Enjoy!