Skip to content
react-fundamentals-19 logo

React 19 Fundamentals

react-fundamentals-19

Complete React 19 fundamentals system. PROACTIVELY activate for: (1) React 19 new features and changes, (2) Server vs Client Components, (3) Server Actions setup, (4) use() hook usage, (5) JSX and component basics, (6) Props and state patterns, (7) Suspense and Error Boundaries, (8) Fragments and...

SKILL.md

Full skill instructions

Quick Reference

FeaturePatternExample
Server ComponentDefault (no directive)async function Page() {}
Client Component'use client' directive'use client'; function Counter() {}
Server Action'use server' directiveasync function submit(formData) {}
use() hookRead promises/​contextconst data = use(promise)
ConceptSyntax
Conditional render{condition && <Component />}
List render{items.map(item => <Item key={item.id} />)}
Props destructurefunction Card({ title, children }) {}
State updatesetItems(prev => [...prev, newItem])

When to Use This Skill

Use for React 19 core concepts:

  • Learning React 19 new features and syntax
  • Deciding between Server and Client Components
  • Setting up Server Actions for forms
  • Understanding the use() hook for async data
  • Component composition and JSX patterns
  • Error handling with Suspense and Error Boundaries

For specific topics: hooks → react-hooks-complete, state management → react-state-management, performance → react-performance


React 19 Fundamentals

Overview

React 19 (released December 2024) introduces significant improvements including the React Compiler, Server Components as first-class citizens, new hooks, and enhanced form handling.

JSX and Components

Function Components

// Basic component
function Greeting({ name }: { name: string }) {
  return <h1>Hello, {name}!</​h1>;
}

// With children
function Card({ children, title }: { children: React.ReactNode; title: string }) {
  return (
    <div className="card">
      <h2>{title}</​h2>
      {children}
    </​div>
  );
}

// Arrow function component
const Button: React.FC<{ onClick: () => void; children: React.ReactNode }> = ({
  onClick,
  children,
}) => (
  <button onClick={onClick}>{children}</​button>
);

JSX Expressions

function ProductCard({ product }: { product: Product }) {
  return (
    <div className="product">
      {/​* Conditional rendering */​}
      {product.onSale && <span className="badge">Sale!</​span>}

      {/​* Ternary */​}
      {product.inStock ? (
        <button>Add to Cart</​button>
      ) : (
        <span>Out of Stock</​span>
      )}

      {/​* Logical AND (short-circuit) */​}
      {product.reviews.length > 0 && (
        <Reviews reviews={product.reviews} />
      )}

      {/​* Mapping arrays */​}
      <ul>
        {product.features.map((feature, index) => (
          <li key={feature.id || index}>{feature.name}</​li>
        ))}
      </​ul>

      {/​* Nullish coalescing */​}
      <span>{product.discount ?? 0}% off</​span>
    </​div>
  );
}

Server vs Client Components

Server Components (Default)

// app/​posts/​page.tsx - Server Component by default
import { db } from '@/​lib/​db';

async function PostsPage() {
  // Direct database access - runs on server only
  const posts = await db.posts.findMany({
    orderBy: { createdAt: 'desc' },
  });

  return (
    <div>
      <h1>Posts</​h1>
      {posts.map((post) => (
        <article key={post.id}>
          <h2>{post.title}</​h2>
          <p>{post.excerpt}</​p>
        </​article>
      ))}
    </​div>
  );
}

export default PostsPage;

Client Components

// components/​Counter.tsx
'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</​p>
      <button onClick={() => setCount((c) => c + 1)}>Increment</​button>
    </​div>
  );
}

Composing Server and Client Components

// Server Component
import { db } from '@/​lib/​db';
import { LikeButton } from './​LikeButton'; // Client Component

async function Post({ id }: { id: string }) {
  const post = await db.posts.findUnique({ where: { id } });

  return (
    <article>
      <h1>{post.title}</​h1>
      <p>{post.content}</​p>
      {/​* Client component for interactivity */​}
      <LikeButton postId={id} initialLikes={post.likes} />
    </​article>
  );
}
// LikeButton.tsx - Client Component
'use client';

import { useState, useTransition } from 'react';
import { likePost } from './​actions';

export function LikeButton({ postId, initialLikes }: { postId: string; initialLikes: number }) {
  const [likes, setLikes] = useState(initialLikes);
  const [isPending, startTransition] = useTransition();

  const handleLike = () => {
    startTransition(async () => {
      const newLikes = await likePost(postId);
      setLikes(newLikes);
    });
  };

  return (
    <button onClick={handleLike} disabled={isPending}>
      {isPending ? 'Liking...' : `Like (${likes})`}
    </​button>
  );
}

Server Actions

Defining Server Actions

// actions.ts
'use server';

import { db } from '@/​lib/​db';
import { revalidatePath } from 'next/​cache';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  const content = formData.get('content') as string;

  await db.posts.create({
    data: { title, content },
  });

  revalidatePath('/​posts');
}

export async function likePost(postId: string) {
  const post = await db.posts.update({
    where: { id: postId },
    data: { likes: { increment: 1 } },
  });

  return post.likes;
}

Using Server Actions in Forms

// Form with Server Action
import { createPost } from './​actions';

function CreatePostForm() {
  return (
    <form action={createPost}>
      <input type="text" name="title" placeholder="Title" required />
      <textarea name="content" placeholder="Content" required />
      <button type="submit">Create Post</​button>
    </​form>
  );
}

Using useActionState

'use client';

import { useActionState } from 'react';
import { createPost } from './​actions';

function CreatePostForm() {
  const [state, formAction, isPending] = useActionState(createPost, {
    error: null,
    success: false,
  });

  return (
    <form action={formAction}>
      <input type="text" name="title" placeholder="Title" required />
      <textarea name="content" placeholder="Content" required />

      {state.error && <p className="error">{state.error}</​p>}
      {state.success && <p className="success">Post created!</​p>}

      <button type="submit" disabled={isPending}>
        {isPending ? 'Creating...' : 'Create Post'}
      </​button>
    </​form>
  );
}

The use() Hook

Reading Promises

import { use, Suspense } from 'react';

// Fetch function that returns a promise
async function fetchComments(postId: string) {
  const res = await fetch(`/​api/​posts/​${postId}/​comments`);
  return res.json();
}

// Component that uses the promise
function Comments({ commentsPromise }: { commentsPromise: Promise<Comment[]> }) {
  const comments = use(commentsPromise);

  return (
    <ul>
      {comments.map((comment) => (
        <li key={comment.id}>{comment.text}</​li>
      ))}
    </​ul>
  );
}

// Parent component
function Post({ postId }: { postId: string }) {
  const commentsPromise = fetchComments(postId);

  return (
    <article>
      <h1>Post Title</​h1>
      <Suspense fallback={<p>Loading comments...</​p>}>
        <Comments commentsPromise={commentsPromise} />
      </​Suspense>
    </​article>
  );
}

Reading Context Conditionally

import { use } from 'react';
import { ThemeContext } from './​ThemeContext';

function ThemedButton({ showTheme }: { showTheme: boolean }) {
  // use() can be called conditionally (unlike useContext)
  if (showTheme) {
    const theme = use(ThemeContext);
    return <button style={{ background: theme.primary }}>Themed</​button>;
  }

  return <button>Default</​button>;
}

Props and State

Props Patterns

// Destructuring props
function UserCard({ user, onEdit, className = '' }: UserCardProps) {
  return (
    <div className={`user-card ${className}`}>
      <h3>{user.name}</​h3>
      <button onClick={() => onEdit(user.id)}>Edit</​button>
    </​div>
  );
}

// Spreading props
function Button({ children, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) {
  return <button {...props}>{children}</​button>;
}

// Default props with TypeScript
interface CardProps {
  title: string;
  elevated?: boolean;
  padding?: 'sm' | 'md' | 'lg';
}

function Card({ title, elevated = false, padding = 'md' }: CardProps) {
  return (
    <div
      className={`card ${elevated ? 'elevated' : ''} padding-${padding}`}
    >
      <h2>{title}</​h2>
    </​div>
  );
}

State Updates

'use client';

import { useState } from 'react';

function TodoList() {
  const [todos, setTodos] = useState<Todo[]>([]);

  // Functional update for derived state
  const addTodo = (text: string) => {
    setTodos((prev) => [
      ...prev,
      { id: Date.now(), text, completed: false },
    ]);
  };

  // Toggle item
  const toggleTodo = (id: number) => {
    setTodos((prev) =>
      prev.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  // Remove item
  const removeTodo = (id: number) => {
    setTodos((prev) => prev.filter((todo) => todo.id !== id));
  };

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>
          <input
            type="checkbox"
            checked={todo.completed}
            onChange={() => toggleTodo(todo.id)}
          />
          <span>{todo.text}</​span>
          <button onClick={() => removeTodo(todo.id)}>Delete</​button>
        </​li>
      ))}
    </​ul>
  );
}

Suspense and Error Boundaries

Suspense for Loading States

import { Suspense } from 'react';

function App() {
  return (
    <div>
      <h1>My App</​h1>

      <Suspense fallback={<HeaderSkeleton />}>
        <Header />
      </​Suspense>

      <Suspense fallback={<SidebarSkeleton />}>
        <Sidebar />
      </​Suspense>

      <Suspense fallback={<ContentSkeleton />}>
        <MainContent />
      </​Suspense>
    </​div>
  );
}

Error Boundaries

'use client';

import { Component, ReactNode } from 'react';

interface Props {
  children: ReactNode;
  fallback: ReactNode;
}

interface State {
  hasError: boolean;
  error?: Error;
}

class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }

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

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('Error caught:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }

    return this.props.children;
  }
}

// Usage
function App() {
  return (
    <ErrorBoundary fallback={<ErrorPage />}>
      <MainContent />
    </​ErrorBoundary>
  );
}

React 19 Error Boundary Hook Pattern

'use client';

import { useErrorBoundary } from 'react-error-boundary';

function DataLoader() {
  const { showBoundary } = useErrorBoundary();

  const loadData = async () => {
    try {
      const data = await fetchData();
      return data;
    } catch (error) {
      showBoundary(error);
    }
  };

  // ...
}

Fragments and Portals

Fragments

// Short syntax
function List() {
  return (
    <>
      <li>Item 1</​li>
      <li>Item 2</​li>
    </>
  );
}

// With key (for mapping)
function DefinitionList({ items }: { items: { term: string; definition: string }[] }) {
  return (
    <dl>
      {items.map((item) => (
        <Fragment key={item.term}>
          <dt>{item.term}</​dt>
          <dd>{item.definition}</​dd>
        </​Fragment>
      ))}
    </​dl>
  );
}

Portals

'use client';

import { createPortal } from 'react-dom';
import { useEffect, useState } from 'react';

function Modal({ children, isOpen }: { children: ReactNode; isOpen: boolean }) {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted || !isOpen) return null;

  return createPortal(
    <div className="modal-overlay">
      <div className="modal-content">{children}</​div>
    </​div>,
    document.body
  );
}

Best Practices

1. Component Organization

src/
  components/
    ui/              # Reusable UI components
      Button.tsx
      Card.tsx
    features/        # Feature-specific components
      auth/
        LoginForm.tsx
        SignupForm.tsx
    layout/          # Layout components
      Header.tsx
      Footer.tsx
  hooks/             # Custom hooks
    useAuth.ts
    useLocalStorage.ts
  lib/               # Utilities and helpers
    utils.ts
    api.ts
  types/             # TypeScript types
    index.ts

2. Naming Conventions

  • Components: PascalCase (UserProfile.tsx)
  • Hooks: camelCase with use prefix (useAuth.ts)
  • Utilities: camelCase (formatDate.ts)
  • Types: PascalCase (User, ApiResponse)

3. Key Prop Usage

// Good - stable unique identifier
{items.map((item) => (
  <Item key={item.id} data={item} />
))}

// Avoid - index as key (unless list is static)
{items.map((item, index) => (
  <Item key={index} data={item} /> // Can cause issues with reordering
))}

4. Avoid Inline Object/​Function Props

// Bad - creates new object/​function every render
<Component style={{ color: 'red' }} onClick={() => handleClick(id)} />

// Good - stable references
const style = useMemo(() => ({ color: 'red' }), []);
const handleClickMemo = useCallback(() => handleClick(id), [id]);
<Component style={style} onClick={handleClickMemo} />

More Other skills

Delegate independent tasks to specialized agents working concurrently with isolated context.

295.4K 206.3K
View

Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.

179.7K 100.1K
View

Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.

179.7K 89.5K
View

A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).

179.7K 76.1K
View

Fundamental design principles for writing maintainable, testable Python code.

40.2K 21.9K
View

Modern responsive layouts using container queries, fluid typography, CSS Grid, and mobile-first strategies.

40.2K 20K
View

Generate Playwright tests from scenarios using interactive browser exploration and validation.

39.7K 18.2K
View

Modern React state management with Redux Toolkit, Zustand, Jotai, and React Query for every state category.

40.2K 14.7K
View

GDPR-compliant data handling with consent management, data subject rights, and privacy controls.

40.2K 14.3K
View

Python error handling patterns including input validation, exception hierarchies, and partial failure handling. Use when implementing validation logic, designing exception strategies, handling batch processing failures, or building robust APIs.

40.2K 13.5K
View

Detailed multi-file refactor planning with safety checks and rollback guidance.

39.7K 13K
View