Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Hamster React

ASecurity

Hamster-specific React and Next.js patterns. Use when creating pages, components, forms, server actions, or data fetching in apps/web. Complements the react-best-practices skill.

2 stars
0 votes
0 copies
0 views
Added 9/27/2026
developmentgoreactnextjsgitapiperformance

Works with

cliapi

Security Analysis

A100/100

Pro scans all 9 files and shows the line behind each finding

Scanned 9/27/2026

$npx -y skills add gethamster/skills --skill hamster-react --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hamster React?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Hamster React
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gethamster-hamster-react/badge)](https://www.skillsdirectory.com/skills/gethamster-hamster-react)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: hamster-react
description: "Hamster-specific React and Next.js patterns. Use when creating pages, components, forms, server actions, or data fetching in apps/web. Complements the react-best-practices skill."
version: "1.1.0"
---

# Hamster React Patterns

## Overview

React and Next.js conventions specific to the Hamster Studio monorepo. Covers page creation, server actions, data fetching, forms, and UI components. For general React performance patterns, see the `react-best-practices` skill.

## When to Apply

- Creating new pages or layouts in apps/web
- Writing server actions or route handlers
- Building forms with validation
- Fetching data in server or client components
- Using @kit/ui components

## Quick Reference

| Task | Pattern | Reference |
| --- | --- | --- |
| Create page | `withI18n`, `generateMetadata`, `PageBody` | `references/rules/page-creation.md` |
| Server action | `enhanceAction` with schema, `'use server'` | `references/rules/server-actions.md` |
| Fetch data | Server: direct Supabase, Client: React Query | `references/rules/data-fetching.md` |
| Build form | react-hook-form + Zod + server action | `references/rules/forms.md` |
| UI components | Import from `@kit/ui/*` | `references/rules/ui-components.md` |

## Architecture Overview

```
app/home/
├── (user)/           # Personal account context
│   ├── _components/  # Route-specific components
│   ├── _lib/server/  # Loaders, actions
│   └── page.tsx
└── [account]/        # Team account context (slug, not UUID)
    ├── _components/
    ├── _lib/server/
    └── page.tsx
```

## Key Patterns

### Page Structure

```tsx
import { PageBody } from '@kit/ui/page';
import { Trans } from '@kit/ui/trans';
import { withI18n } from '~/lib/i18n/with-i18n';

export const generateMetadata = async () => {
  const i18n = await createI18nServerInstance();
  return { title: i18n.t('feature:pageTitle') };
};

function FeaturePage() {
  return (
    <>
      <FeatureHeader title={<Trans i18nKey="common:routes.feature" />} />
      <PageBody>{/* Content */}</PageBody>
    </>
  );
}

export default withI18n(FeaturePage);
```

### Server Action Pattern

```tsx
'use server';

import { enhanceAction } from '@kit/next/actions';
import { CreateItemSchema } from '../schema/create-item.schema';

export const createItemAction = enhanceAction(
  async (data, user) => {
    // data validated, user authenticated
    const client = getSupabaseServerClient();
    const { data: item } = await client.from('items').insert(data).select().single();
    return { success: true, item };
  },
  { auth: true, schema: CreateItemSchema }
);
```

### Data Fetching Decision

| Context | Use | Example |
| --- | --- | --- |
| Server Component | Direct Supabase | `await client.from('items').select()` |
| Client Component | React Query + `useSupabase` | `useQuery({ queryFn: ... })` |
| Admin bypass | `getSupabaseServerAdminClient` | Rare, requires manual auth |

### Form Pattern

```tsx
'use client';

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Form, FormField, FormItem, FormControl, FormMessage } from '@kit/ui/form';
import { toast } from '@kit/ui/sonner';

function MyForm() {
  const form = useForm({ resolver: zodResolver(Schema) });

  const onSubmit = (data) => {
    startTransition(async () => {
      await toast.promise(myAction(data), {
        loading: t('creating'),
        success: t('created'),
        error: t('error')
      });
    });
  };

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)}>
        {/* FormFields */}
      </form>
    </Form>
  );
}
```

## useEffect Rules (CRITICAL)

**MUST** follow [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect). Before writing any `useEffect`, ask: _"Is this synchronizing with an external system?"_ If not, you probably don't need it.

### When useEffect is WRONG

#### 1. Derived state — compute during render instead

```tsx
// 🔴 WRONG: redundant state + unnecessary Effect
const [fullName, setFullName] = useState('');
useEffect(() => {
  setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);

// ✅ CORRECT: calculate during render
const fullName = firstName + ' ' + lastName;

// ✅ CORRECT: memoize if expensive
const filtered = useMemo(() => getFilteredTodos(todos, filter), [todos, filter]);
```

#### 2. State reset on prop change — use `key` or render-time adjustment

```tsx
// 🔴 WRONG: resetting state in an Effect
useEffect(() => {
  setComment('');
}, [userId]);

// ✅ BEST: use key to reset entire component
<Profile userId={userId} key={userId} />

// ✅ OK: render-time adjustment when only partial reset needed
const [prevItems, setPrevItems] = useState(items);
if (items !== prevItems) {
  setPrevItems(items);
  setSelection(null);
}

// ✅ BEST: derive instead of resetting
const selection = items.find(item => item.id === selectedId) ?? null;
```

#### 3. Event-specific logic — put it in the event handler

```tsx
// 🔴 WRONG: event logic in an Effect
useEffect(() => {
  if (product.isInCart) {
    showNotification(`Added ${product.name}!`);
  }
}, [product]);

// ✅ CORRECT: call from the event handler
function handleBuyClick() {
  addToCart(product);
  showNotification(`Added ${product.name}!`);
}
```

#### 4. Notifying parent about state changes — call in the event handler

```tsx
// 🔴 WRONG: notifying parent via Effect
useEffect(() => {
  onChange(isOn);
}, [isOn, onChange]);

// ✅ CORRECT: notify during the event that caused the change
function updateToggle(nextIsOn) {
  setIsOn(nextIsOn);
  onChange(nextIsOn);
}
```

#### 5. Passing data to parent — lift the fetch up instead

```tsx
// 🔴 WRONG: child fetches, passes to parent via Effect
function Child({ onFetched }) {
  const data = useSomeAPI();
  useEffect(() => {
    if (data) onFetched(data);
  }, [data, onFetched]);
}

// ✅ CORRECT: parent fetches, passes down
function Parent() {
  const data = useSomeAPI();
  return <Child data={data} />;
}
```

#### 6. Effect chains — compute in render, update in event handlers

```tsx
// 🔴 WRONG: chain of Effects triggering each other
useEffect(() => { if (card?.gold) setGoldCount(c => c + 1); }, [card]);
useEffect(() => { if (goldCount > 3) { setRound(r => r + 1); setGoldCount(0); } }, [goldCount]);
useEffect(() => { if (round > 5) setGameOver(true); }, [round]);

// ✅ CORRECT: derive what you can, update in event handler
const isGameOver = round > 5;
function handlePlaceCard(nextCard) {
  setCard(nextCard);
  if (nextCard.gold) {
    if (goldCount < 3) setGoldCount(goldCount + 1);
    else { setGoldCount(0); setRound(round + 1); }
  }
}
```

### When useEffect IS correct

| Pattern | Why it's correct |
| --- | --- |
| Subscriptions with cleanup | Synchronizing with external system (realtime channels, WebSocket, event listeners) |
| Data fetching with cleanup | Synchronizing with network (add `ignore` flag for race conditions) |
| DOM manipulation via refs | Synchronizing with browser DOM (focus, scroll, ResizeObserver) |
| Analytics on mount | Side effect because component was _displayed_ |
| Ref syncs for stale closures | Keeping refs current for callbacks used in subscriptions |
| External store mutations | Synchronizing React state with Zustand/external stores |

### Key principle

> **"If this logic is caused by a particular interaction, keep it in the event handler. If it's caused by the user _seeing_ the component on the screen, keep it in the Effect."**

### Lint enforcement

The codebase enforces these patterns via:

- `react-hooks/set-state-in-effect` — flags synchronous setState inside effects (use `useEffectEvent` wrapper for legitimate cases like hydration detection)
- `react-hooks/refs` — flags ref access during render (keep ref syncs in `useEffect`, not render body)
- Consider a community “you might not need an effect” lint plugin for broader detection of redundant effects

## Component Guidelines

### Server vs Client Components

| Use Server Components | Use Client Components |
| --- | --- |
| Data fetching | Interactivity (onClick, onChange) |
| Authenticated queries | Browser APIs |
| Static rendering | React hooks (useState, useEffect) |
| No hooks needed | Real-time listeners |

### Workspace Contexts

```tsx
// Personal account
import { useUserWorkspace } from '@kit/accounts/hooks/use-user-workspace';
const { user, account } = useUserWorkspace();

// Team account
import { useTeamAccountWorkspace } from '@kit/team-accounts/hooks/use-team-account-workspace';
const { account, user, accounts } = useTeamAccountWorkspace();
```

### JSX Patterns

```tsx
// Class merging
import { cn } from '@kit/ui/utils';
<div className={cn('base', { 'active': isActive }, className)} />

// Conditional rendering
import { If } from '@kit/ui/if';
<If condition={isLoading} fallback={<Content />}>
  <Spinner />
</If>

// Translations (no hardcoded strings)
import { Trans } from '@kit/ui/trans';
<Trans i18nKey="feature:message" values={{ name }} />
```

## File Organization

| File | Purpose |
| --- | --- |
| `page.tsx` | Route page component |
| `layout.tsx` | Shared layout |
| `loading.tsx` | Loading state |
| `error.tsx` | Error boundary |
| `_components/` | Route-specific components |
| `_lib/server/` | Loaders, actions, queries |
| `_lib/schema/` | Zod validation schemas |

## References

- `references/rules/page-creation.md` - Creating pages and layouts
- `references/rules/server-actions.md` - Server action patterns
- `references/rules/data-fetching.md` - Data fetching strategies
- `references/rules/forms.md` - Form implementation
- `references/rules/ui-components.md` - UI component usage
- `references/rules/react-patterns.md` - React component patterns
- `references/rules/translations.md` - i18n implementation

Attribution

gethamstergethamster
View sourceSee grades on GitHubMore from gethamster →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

286712 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Writing Plans

Use when you have a spec or requirements for a multi-step task, before touching code

2927051 votes
View all in development →