React logoReactv19BEGINNER

React Components & JSX

React components cheat sheet covering JSX syntax, props, conditional rendering, lists, event handling, and composition patterns.

12 min read
reactjsxcomponentspropsconditional-renderinglists

Sign in to mark items as known and track your progress.

Sign in

Component Essentials

Core concepts for building React components

Function Components

Modern way to create React components

📄 Codejavascript
// Simple function component
function Welcome() {
  return <h1>Hello, World!</h1>
}

// Arrow function syntax
const Welcome = () => {
  return <h1>Hello, World!</h1>
}

// Using the component
function App() {
  return (
    <div>
      <Welcome />
      <Welcome />
    </div>
  )
}
🟢 Essential - Use function components for all new code
💡 Component names must start with capital letter
📌 Returns JSX to describe the UI
componentsessential

Basic Props

Pass data to components via props

📄 Codejavascript
// Component with props
function Greeting({ name, age }) {
  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>Age: {age}</p>
    </div>
  )
}

// Using with props
function App() {
  return (
    <div>
      <Greeting name="Alice" age={25} />
      <Greeting name="Bob" age={30} />
    </div>
  )
}
🟢 Essential - Props make components reusable
💡 Props are read-only, never modify them
📌 Pass any JavaScript value as a prop
propsessential

Default Props

Set default values for optional props

javascript
// Default props with destructuring
function Button({ 
  text, 
  color = 'blue',
  size = 'medium' 
}) {
  return (
    <button className={'btn-' + size} style={{ color }}>
      {text}
    </button>
  )
}

// Some props use defaults, some don't
<Button text="Click me" />
<Button text="Submit" color="green" size="large" />
💡 Use = in destructuring for clean defaults
📌 Default values only used if prop is undefined
⚡ Defaults make components more flexible
⚛️ React 19 removed defaultProps for function components - use default params (shown here)
propsdefaults

Children Prop

Pass JSX content between component tags

📄 Codejavascript
// Component with children
function Card({ children, title }) {
  return (
    <div className="card">
      <h2>{title}</h2>
      <div className="content">
        {children}
      </div>
    </div>
  )
}

// Pass content as children
function App() {
  return (
    <Card title="User Info">
      <p>Name: John Doe</p>
      <p>Email: john@example.com</p>
      <button>Edit</button>
    </Card>
  )
}
🟢 Essential - Children enables component composition
💡 Anything between tags becomes children prop
📌 Can be text, elements, or other components
propschildrencomposition

Event Handlers

Handle user interactions with events

📄 Codejavascript
// Click event
function Button() {
  const handleClick = () => {
    alert('Clicked!')
  }
  
  return <button onClick={handleClick}>Click me</button>
}

// Event with parameters
function Item({ id, name, onDelete }) {
  return (
    <div>
      <span>{name}</span>
      <button onClick={() => onDelete(id)}>Delete</button>
    </div>
  )
}

// Using the component
function App() {
  const handleDelete = (itemId) => {
    console.log('Deleting:', itemId)
  }
  
  return <Item id={1} name="Task" onDelete={handleDelete} />
}
🟢 Essential - Events enable interactivity
💡 Use arrow functions to pass parameters
⚠️ Don't call the function: onClick={handleClick} not onClick={handleClick()}
eventshandlersessential

Component Import/Export

Organize components in separate files

javascript
// Button.js - Export component
function Button({ text, onClick }) {
  return <button onClick={onClick}>{text}</button>
}

export default Button

// App.js - Import and use
import Button from './Button'

function App() {
  return (
    <div>
      <h1>My App</h1>
      <Button text="Click me" onClick={() => alert('Hi!')} />
    </div>
  )
}
💡 One component per file is common practice
📌 Use default export for main component
⚡ Named exports for utility components
importexportmodules

Keeping Components Pure

Components must be pure functions of their props and state

jsx
// ❌ IMPURE — mutates external state
let count = 0;
function Counter() {
  count++; // side effect during render
  return <div>{count}</div>;
}

// ✅ PURE — same input, same output
function Counter({ count }) {
  return <div>{count}</div>;
}
💡 Pure components are predictable, easier to test, and enable React optimizations
⚡ React assumes components are pure — breaking this rule causes subtle bugs
📌 Side effects belong in event handlers or useEffect, never in render
🟢 StrictMode double-renders in dev to catch impure components early
purerenderside-effects

JSX Fundamentals

JavaScript XML syntax for describing UI in React

JSX Basics

JavaScript XML syntax for React

📄 Codejavascript
// JSX looks like HTML but it's JavaScript
function Welcome() {
  return <h1>Hello World</h1>
}

// Multi-line JSX needs parentheses
function Card() {
  return (
    <div className="card">
      <h2>Title</h2>
      <p>Content</p>
    </div>
  )
}

// JSX compiles to JavaScript
// <h1>Hi</h1> becomes React.createElement('h1', null, 'Hi')
🟢 Essential - JSX is JavaScript, not HTML
💡 Use parentheses for multi-line JSX
📌 Must return a single root element
jsxsyntaxessential

JSX Expressions

Embed JavaScript expressions in JSX

📄 Codejavascript
function UserCard() {
  const name = 'Alice'
  const age = 25
  const isAdult = age >= 18
  
  return (
    <div>
      {/* Variables */}
      <h2>{name}</h2>
      
      {/* Math expressions */}
      <p>Age: {age + 1} next year</p>
      
      {/* Ternary operator */}
      <p>{isAdult ? 'Can vote' : 'Too young'}</p>
      
      {/* Function calls */}
      <p>Uppercase: {name.toUpperCase()}</p>
    </div>
  )
}
🟢 Essential - Use {} to embed any JS expression
💡 Expressions produce values, statements don't
⚠️ Can't use if/for/while directly, use ternary or map
jsxexpressionsessential

JSX Attributes

HTML attributes in JSX use camelCase

📄 Codejavascript
function Form() {
  return (
    <div>
      {/* className instead of class */}
      <div className="container">
        
        {/* htmlFor instead of for */}
        <label htmlFor="name">Name:</label>
        <input id="name" type="text" />
        
        {/* camelCase attributes */}
        <input 
          autoFocus
          tabIndex={0}
          placeholder="Enter text"
        />
        
        {/* Event handlers are camelCase */}
        <button onClick={() => alert('Hi!')}>
          Click Me
        </button>
      </div>
    </div>
  )
}
💡 Use className instead of class
📌 Use htmlFor instead of for
⚡ All attributes use camelCase naming
jsxattributes

Inline Styles

Apply styles using JavaScript objects

📄 Codejavascript
function StyledComponent() {
  const styles = {
    color: 'blue',
    fontSize: '20px',
    backgroundColor: '#f0f0f0',
    padding: '10px'
  }
  
  return (
    <div>
      {/* Style object */}
      <h1 style={styles}>Styled heading</h1>
      
      {/* Inline style object */}
      <p style={{ 
        color: 'red', 
        fontWeight: 'bold' 
      }}>
        Inline styled text
      </p>
      
      {/* Dynamic styles */}
      <div style={{
        backgroundColor: true ? 'green' : 'red',
        width: '100px',
        height: '100px'
      }} />
    </div>
  )
}
💡 Style attribute takes an object, not string
📌 Use camelCase for CSS properties
⚡ Values are strings or numbers (px assumed)
jsxstylescss

Conditional Rendering

Show/hide elements based on conditions

📄 Codejavascript
function Notifications({ user, count }) {
  return (
    <div>
      {/* Ternary operator */}
      {user ? (
        <h1>Welcome, {user.name}!</h1>
      ) : (
        <h1>Please log in</h1>
      )}
      
      {/* Logical && operator */}
      {count > 0 && (
        <p>You have {count} new messages</p>
      )}
      
      {/* Logical || for defaults */}
      <p>Name: {user?.name || 'Guest'}</p>
      
      {/* Prevent rendering with null */}
      {count === 0 ? null : <span>({count})</span>}
    </div>
  )
}
🟢 Essential - && shows element if condition is true
💡 Ternary (? :) for if-else rendering
⚠️ Remember: 0 and empty string render, null/undefined don't
jsxconditionalessential

Lists & Keys

Render arrays with map and unique keys

javascript
function TodoList() {
  const todos = [
    { id: 1, text: 'Learn React' },
    { id: 2, text: 'Build an app' },
    { id: 3, text: 'Deploy it' }
  ]
  
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>
          {todo.text}
        </li>
      ))}
    </ul>
  )
}
🟢 Essential - Always include key prop in lists
💡 Keys help React track changes efficiently
⚠️ Keys must be unique among siblings
jsxlistskeysessential

Fragments

Return multiple elements without wrapper

📄 Codejavascript
import { Fragment } from 'react'

// Long syntax with Fragment
function LongForm() {
  return (
    <Fragment>
      <h1>Title</h1>
      <p>Paragraph</p>
    </Fragment>
  )
}

// Short syntax (preferred)
function ShortForm() {
  return (
    <>
      <h1>Title</h1>
      <p>Paragraph</p>
    </>
  )
}

// Only Fragment can have key prop
function ListItems({ items }) {
  return (
    <>
      {items.map(item => (
        <Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.definition}</dd>
        </Fragment>
      ))}
    </>
  )
}
💡 Fragments avoid extra wrapper divs
📌 Use <> </> shorthand in most cases
⚡ Only Fragment accepts key prop
jsxfragments

JSX Comments

Add comments in JSX code

📄 Codejavascript
function Comments() {
  return (
    <div>
      {/* Single line comment */}
      <h1>Title</h1>
      
      {/* 
        Multi-line
        comment
      */}
      <p>Content</p>
      
      {/* TODO: Add more content */}
      
      {/* Conditional comment
      {false && <p>This won't render</p>}
      */}
    </div>
  )
}

// Regular JS comments work outside JSX
// This is a normal comment
function Component() {
  // Another normal comment
  return <div>Content</div>
}
💡 JSX comments must be inside {/* */}
📌 Regular // comments work outside JSX
⚡ Comments don't appear in rendered HTML
jsxcomments

Forms & Controlled Components

Build interactive forms with controlled and uncontrolled components

Controlled Inputs

Form inputs controlled by React state

📄 Codejavascript
function Form() {
  const [name, setName] = React.useState('')
  
  return (
    <div>
      <input 
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Enter name"
      />
      <p>Hello, {name}!</p>
    </div>
  )
}
🟢 Essential - React controls the input value
💡 Value comes from state, onChange updates state
📌 Single source of truth for form data
formscontrolledessential

Form Submission

Handle form submit events

📄 Codejavascript
function LoginForm() {
  const [email, setEmail] = React.useState('')
  const [password, setPassword] = React.useState('')
  
  const handleSubmit = (e) => {
    e.preventDefault() // Prevent page reload
    console.log('Login:', email, password)
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        required
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        required
      />
      <button type="submit">Login</button>
    </form>
  )
}
⚠️ Always preventDefault() on form submit
💡 Form validates before onSubmit fires
📌 Button type="submit" triggers form submission
formssubmit

Select & Textarea

Controlled select dropdowns and textareas

📄 Codejavascript
function Survey() {
  const [country, setCountry] = React.useState('us')
  const [comments, setComments] = React.useState('')
  
  return (
    <div>
      {/* Controlled select */}
      <select 
        value={country} 
        onChange={(e) => setCountry(e.target.value)}
      >
        <option value="us">United States</option>
        <option value="uk">United Kingdom</option>
        <option value="ca">Canada</option>
      </select>
      
      {/* Controlled textarea */}
      <textarea
        value={comments}
        onChange={(e) => setComments(e.target.value)}
        rows={4}
        placeholder="Your comments..."
      />
      
      <p>Selected: {country}</p>
      <p>Comments: {comments}</p>
    </div>
  )
}
💡 Select uses value prop, not selected attribute
📌 Textarea uses value prop, not children
⚡ Same pattern as input elements
formsselecttextarea

Checkboxes & Radio

Handle checkbox and radio button inputs

📄 Codejavascript
function Preferences() {
  const [subscribe, setSubscribe] = React.useState(false)
  const [frequency, setFrequency] = React.useState('weekly')
  
  return (
    <div>
      {/* Checkbox */}
      <label>
        <input
          type="checkbox"
          checked={subscribe}
          onChange={(e) => setSubscribe(e.target.checked)}
        />
        Subscribe to newsletter
      </label>
      
      {/* Radio buttons */}
      <div>
        <label>
          <input
            type="radio"
            value="daily"
            checked={frequency === 'daily'}
            onChange={(e) => setFrequency(e.target.value)}
          />
          Daily
        </label>
        <label>
          <input
            type="radio"
            value="weekly"
            checked={frequency === 'weekly'}
            onChange={(e) => setFrequency(e.target.value)}
          />
          Weekly
        </label>
      </div>
    </div>
  )
}
💡 Checkbox uses checked prop and e.target.checked
📌 Radio buttons share same state variable
⚡ Name attribute groups radio buttons
formscheckboxradio

Context API

Share data across components without prop drilling

Context API

Create, provide, and consume context with createContext and useContext

jsx
import { createContext, useContext, useState } from 'react';

const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('dark');
  return (
    <ThemeContext.Provider value={theme}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div className={theme}>Toolbar</div>;
}
💡 Context is for data many components need — theme, auth, locale, language
⚡ Wrap useContext in a custom hook (useTheme) for type safety and better errors
📌 Every consumer re-renders when the Provider value changes — split contexts to limit re-renders
🟢 React 19+ lets you use <Context value={...}> directly without .Provider
contextproviderusecontext

Component Patterns & Types

Advanced patterns for type safety and component composition

Composition with children

Use the children prop to build flexible, composable layout components

jsx
function Card({ children }) {
  return <div className="card">{children}</div>;
}

function App() {
  return (
    <Card>
      <h2>Title</h2>
      <p>Content</p>
    </Card>
  );
}
💡 Composition is React favorite pattern — solves most "inheritance" needs cleanly
⚡ Use named slot props (header, sidebar) when you need multiple "children" areas
📌 Composition avoids prop drilling without needing Context for layout components
🟢 Function-as-children gives the parent control while letting children access internal data
compositionchildrenslots

PropTypes & TypeScript

Add type checking to React components

typescript
// TypeScript (recommended) - compile-time prop checking
interface UserProps {
  name: string
  age?: number
  email: string
}

function User({ name, age = 0, email }: UserProps) {
  return <div>{name}, {age}, {email}</div>
}

// React 19 removed runtime propTypes - assigning User.propTypes
// is now ignored. For runtime validation, use a schema like Zod.
⚛️ TypeScript for compile-time checks; Zod for runtime validation
⚠️ React 19 removed propTypes - assigning .propTypes is silently ignored
💡 TypeScript gives better IDE support, autocomplete, and refactoring
📌 Use discriminated unions for mutually exclusive component variants

Refs & forwardRef

Access DOM elements and pass refs through components

javascript
// Basic ref - access a DOM node imperatively
function TextInput() {
  const inputRef = useRef(null)

  const focusInput = () => {
    inputRef.current.focus()
  }

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  )
}

// React 19: ref is a regular prop - no forwardRef needed
function FancyInput({ ref, ...props }) {
  return <input ref={ref} className="fancy-input" {...props} />
}
⚛️ Refs give imperative access to DOM nodes
💡 React 19: pass ref as a normal prop; forwardRef still works but is deprecated
📌 Refs persist across renders without causing a re-render
⚠️ Prefer declarative patterns - reach for refs only when you must

Compound Components

Build flexible APIs with related components that share state

jsx
function Tabs({ children, defaultTab }) {
  const [active, setActive] = useState(defaultTab);
  return (
    <TabsContext.Provider value={{ active, setActive }}>
      {children}
    </TabsContext.Provider>
  );
}

Tabs.List = TabList;
Tabs.Tab = Tab;
Tabs.Panel = TabPanel;
💡 Compound components give consumers full control over markup while sharing state
⚡ Used by libraries like Radix UI, shadcn/ui, and React Aria for flexible primitives
📌 Attach children as static properties (Tabs.Tab) for a clean discoverable API
🟢 Internal Context shares state without exposing it as props on every child
compoundpatterncontext

Higher-Order Components (HOCs)

Functions that take a component and return an enhanced component

jsx
function withLogger(Component) {
  return function Wrapped(props) {
    console.log('Rendering', Component.name, props);
    return <Component {...props} />;
  };
}

const LoggedButton = withLogger(Button);
💡 HOCs are functions that wrap a component to add behavior — common in legacy code
⚡ Modern React prefers custom hooks over HOCs for sharing logic
📌 Always spread {...props} to forward unrelated props to the wrapped component
🟢 HOCs are still useful for cross-cutting concerns like auth guards and analytics
hocpatterncomposition

Render Props

Share logic by passing a render function as a prop

jsx
function MouseTracker({ render }) {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  useEffect(() => {
    const move = (e) => setPos({ x: e.clientX, y: e.clientY });
    window.addEventListener('mousemove', move);
    return () => window.removeEventListener('mousemove', move);
  }, []);
  return render(pos);
}

<MouseTracker render={({ x, y }) => <p>{x}, {y}</p>} />
💡 Render props let a component share state/logic while letting consumers control rendering
⚡ Modern React replaces most render props with custom hooks for cleaner JSX
📌 Render props are still useful when you need access to the component lifecycle in JSX
🟢 Children-as-function is a render prop variant — same idea, cleaner syntax
render-propspattern

Optimization & Advanced Features

Performance optimization and advanced React features

Suspense & lazy()

Code-split components and show fallback UI while loading

jsx
import { lazy, Suspense } from 'react';

const HeavyChart = lazy(() => import('./HeavyChart'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyChart />
    </Suspense>
  );
}
💡 lazy() splits the component into its own JS bundle - only loaded when rendered
⚡ Use multiple Suspense boundaries to load page sections independently
📌 Route-level code splitting is the biggest bundle-size win for most apps
🟢 Suspense also works with data libraries that support it (Relay, TanStack Query)
suspenselazycode-splitting

Error Boundaries

Catch render errors in child components and show fallback UI

jsx
class ErrorBoundary extends Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    console.error(error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}
💡 Error boundaries must be class components — there is no hook equivalent (yet)
⚡ Use react-error-boundary library for a cleaner functional API
📌 Wrap risky subtrees independently so one error doesn't take down the whole app
🟢 Error boundaries do NOT catch async errors or event handler errors — use try/catch there
error-boundaryerrorclass

React.memo & Optimization

Optimize component re-renders with memoization

javascript
// React.memo
const ExpensiveComponent = React.memo(function Component({ data }) {
  return <div>{data.value}</div>
})

// Custom comparison
const MyComponent = React.memo(Component, (prevProps, nextProps) => {
  // Return true if props are equal (skip re-render)
  return prevProps.id === nextProps.id
})
⚡ React 19's compiler auto-memoizes - reach for manual memo/useMemo/useCallback only when profiling shows a real need
⚛️ React.memo skips re-renders when props are unchanged
💡 useMemo caches expensive computations; useCallback stabilizes function identity
⚠️ Profile before optimizing - premature memoization hurts maintainability

Styling Components

Different approaches to styling React components

javascript
// Inline Styles
<div style={{ backgroundColor: 'blue', padding: '10px' }}>
  Inline styled
</div>

// CSS Classes
<div className="card primary-card">
  CSS Classes
</div>

// CSS Modules
import styles from './Component.module.css'
<div className={styles.card}>CSS Module</div>

// Styled Components
import styled from 'styled-components'
const Button = styled.button`
  background: ${props => props.primary ? 'blue' : 'gray'};
  color: white;
  padding: 10px;
`
⚛️ Choose styling approach based on project needs
💡 CSS Modules provide scoped styles without runtime cost
📌 CSS-in-JS offers dynamic styling with JS power
⚠️ Inline styles can't use pseudo-classes or media queries
⚡ Utility-first CSS (Tailwind) for rapid development

Portals (createPortal)

Render children into a different DOM node outside the parent hierarchy

jsx
import { createPortal } from 'react-dom';

function Modal({ children, onClose }) {
  return createPortal(
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal">{children}</div>
    </div>,
    document.body
  );
}
💡 Portals render into any DOM node but stay in the React tree — events bubble normally
⚡ Use portals for modals, tooltips, dropdowns — anything that needs to escape overflow:hidden
📌 Even though the DOM node is elsewhere, Context, refs, and events all work as expected
🟢 Stop click propagation on the inner content to prevent overlay clicks from closing the modal
portalmodaltooltip

StrictMode

Catch bugs early by enabling extra development checks

jsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>
);
💡 StrictMode runs in dev only — no production impact, no perf cost
⚡ Double-rendering surfaces impure components and missing cleanup early
📌 If your console.log fires twice in dev, that's StrictMode catching a side effect
🟢 You can wrap individual subtrees in StrictMode for gradual adoption
strict-modedevdebugging