react-use-state

Guides proper usage of React useState hook. Use this skill when adding state to components, deciding between useState vs alternatives, or troubleshooting state update issues.

210 stars

Best use case

react-use-state is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Guides proper usage of React useState hook. Use this skill when adding state to components, deciding between useState vs alternatives, or troubleshooting state update issues.

Teams using react-use-state should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/react-use-state/SKILL.md --create-dirs "https://raw.githubusercontent.com/flpbalada/my-opencode-config/main/skills/react-use-state/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/react-use-state/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How react-use-state Compares

Feature / Agentreact-use-stateStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Guides proper usage of React useState hook. Use this skill when adding state to components, deciding between useState vs alternatives, or troubleshooting state update issues.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# React: useState Hook Best Practices

## Core Concept

`useState` is a React Hook that adds a state variable to your component, triggering re-renders when the state changes.

```jsx
const [state, setState] = useState(initialState);
```

## When to Use useState

### Ideal Use Cases

| Use Case | Example |
|----------|---------|
| **Form inputs** | `const [name, setName] = useState('')` |
| **UI state** | `const [isOpen, setIsOpen] = useState(false)` |
| **Simple counters** | `const [count, setCount] = useState(0)` |
| **Local component data** | `const [items, setItems] = useState([])` |

### Use useState When

- State is **local** to the component
- State transitions are **simple** (direct value replacement)
- Changes should **trigger re-renders**
- You need to **persist values** between renders

## When NOT to Use useState

### Use useRef Instead

When you need mutable values that **don't trigger re-renders**:

```jsx
// Interval IDs, DOM references, previous values
const intervalRef = useRef(null);
const inputRef = useRef(null);
```

### Use useReducer Instead

When state logic is **complex**:

```jsx
// Multiple related values, complex transitions
const [state, dispatch] = useReducer(reducer, initialState);
```

Use `useReducer` when:
- State has multiple sub-values
- Next state depends on previous state in complex ways
- You want to centralize state logic

### Avoid Redundant State

If a value can be **computed from props or other state**, don't store it:

```jsx
// BAD: Redundant state
const [fullName, setFullName] = useState('');
useEffect(() => {
  setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);

// GOOD: Compute during render
const fullName = `${firstName} ${lastName}`;

// If expensive, use useMemo
const sortedItems = useMemo(() => 
  items.sort((a, b) => a.name.localeCompare(b.name)), 
  [items]
);
```

### Don't Use for Global/Shared State

For state shared across multiple components:
- **React Context** for moderate sharing
- **External stores** (Zustand, Jotai) for complex apps
- **Server state libraries** (TanStack Query) for async data

## Critical Rules

### 1. Never Mutate State Directly

```jsx
// BAD: Mutation
obj.x = 10;
setObj(obj); // React ignores this!

// GOOD: Create new object
setObj({ ...obj, x: 10 });

// BAD: Array mutation
arr.push(item);
setArr(arr); // React ignores this!

// GOOD: Create new array
setArr([...arr, item]);
```

### 2. State Updates Are Asynchronous

```jsx
function handleClick() {
  setCount(count + 1);
  console.log(count); // Still old value!
  
  // If you need the new value:
  const nextCount = count + 1;
  setCount(nextCount);
  console.log(nextCount); // New value
}
```

### 3. Use Updater Function for Sequential Updates

```jsx
// BAD: Only increments by 1
function handleClick() {
  setCount(count + 1); // 0 + 1 = 1
  setCount(count + 1); // 0 + 1 = 1 (same stale value!)
  setCount(count + 1); // 0 + 1 = 1
}

// GOOD: Increments by 3
function handleClick() {
  setCount(c => c + 1); // 0 -> 1
  setCount(c => c + 1); // 1 -> 2
  setCount(c => c + 1); // 2 -> 3
}
```

### 4. Use Initializer Function for Expensive Initial Values

```jsx
// BAD: createTodos() runs every render
const [todos, setTodos] = useState(createTodos());

// GOOD: createTodos runs only once
const [todos, setTodos] = useState(createTodos);

// Or with arrow function for arguments
const [todos, setTodos] = useState(() => createTodos(userId));
```

### 5. Call Hooks at Top Level Only

```jsx
// BAD: Conditional hook
if (condition) {
  const [state, setState] = useState(0); // Error!
}

// GOOD: Always call, conditionally use
const [state, setState] = useState(0);
if (condition) {
  // use state here
}
```

## Common Patterns

### Resetting State with Key

```jsx
// Parent controls reset via key
<Form key={version} />

// When version changes, Form remounts with fresh state
```

### Storing Functions in State

```jsx
// BAD: Function gets called
const [fn, setFn] = useState(someFunction);

// GOOD: Wrap in arrow function
const [fn, setFn] = useState(() => someFunction);
setFn(() => newFunction);
```

### Updating Objects/Arrays

```jsx
// Object: spread and override
setForm({ ...form, email: newEmail });

// Nested object
setUser({
  ...user,
  address: { ...user.address, city: newCity }
});

// Array: filter, map, spread
setItems(items.filter(i => i.id !== id));        // Remove
setItems([...items, newItem]);                    // Add
setItems(items.map(i => i.id === id ? {...i, done: true} : i)); // Update
```

## Quick Reference

### DO

- Use for simple, local component state
- Create new objects/arrays when updating
- Use updater function when depending on previous state
- Use initializer function for expensive initial values

### DON'T

- Store computed/derived values
- Mutate existing state objects/arrays
- Read state immediately after setting (it's a snapshot)
- Call `setState` unconditionally during render

## Alternative Hooks Comparison

| Hook | Use When |
|------|----------|
| `useState` | Simple state, primitives, basic objects |
| `useReducer` | Complex state logic, multiple sub-values |
| `useRef` | Mutable values without re-renders |
| `useMemo` | Expensive computed values |
| `useContext` | State shared across component tree |

## References

- [React Docs - useState](https://react.dev/reference/react/useState)
- [React Docs - State as a Snapshot](https://react.dev/learn/state-as-a-snapshot)
- [React Docs - Choosing the State Structure](https://react.dev/learn/choosing-the-state-structure)

Related Skills

react-useeffect-avoid

210
from flpbalada/my-opencode-config

Guides when NOT to use useEffect and suggests better alternatives. Use when reviewing React code, troubleshooting performance, or considering useEffect for derived state or form resets.

react-use-client-boundary

210
from flpbalada/my-opencode-config

Guides proper usage of "use client" directive in React/Next.js. Use this skill when adding client components, troubleshooting Server Component errors, or deciding where to place the client boundary.

react-use-callback

210
from flpbalada/my-opencode-config

Guides proper usage of the useCallback hook in React. Use this skill when optimizing function references, passing callbacks to memoized components, or preventing unnecessary re-renders.

react-key-prop

210
from flpbalada/my-opencode-config

Guides proper usage of the key prop in React lists. Use this skill when rendering lists, mapping arrays to components, or troubleshooting list-related state bugs.

what-not-to-do-as-product-manager

210
from flpbalada/my-opencode-config

Anti-patterns and mistakes to avoid as a product manager. Use when evaluating leadership behaviors, improving team dynamics, reflecting on management practices, or onboarding new product managers.

visual-cues-cta-psychology

210
from flpbalada/my-opencode-config

Design effective CTAs using visual attention and gaze psychology principles. Use when designing landing pages, button hierarchies, conversion elements, or optimizing user attention flow through interfaces.

vercel-sandbox

210
from flpbalada/my-opencode-config

Run agent-browser + Chrome inside Vercel Sandbox microVMs for browser automation from any Vercel-deployed app. Use when the user needs browser automation in a Vercel app (Next.js, SvelteKit, Nuxt, Remix, Astro, etc.), wants to run headless Chrome without binary size limits, needs persistent browser sessions across commands, or wants ephemeral isolated browser environments. Triggers include "Vercel Sandbox browser", "microVM Chrome", "agent-browser in sandbox", "browser automation on Vercel", or any task requiring Chrome in a Vercel Sandbox.

value-realization

210
from flpbalada/my-opencode-config

Analyze if end users discover clear value. Use when evaluating product concepts, analyzing adoption, or uncertain about direction.

user-story-fundamentals

210
from flpbalada/my-opencode-config

Capture requirements from user perspective with structured user stories. Use when writing backlog items, defining acceptance criteria, prioritizing features, or communicating requirements between product and development.

typescript-satisfies-operator

210
from flpbalada/my-opencode-config

Guides proper usage of TypeScript's satisfies operator vs type annotations. Use this skill when deciding between type annotations (colon) and satisfies, validating object shapes while preserving literal types, or troubleshooting type inference issues.

typescript-interface-vs-type

210
from flpbalada/my-opencode-config

Guides when to use interface vs type in TypeScript. Use this skill when defining object types, extending types, or choosing between interface and type aliases.

typescript-best-practices

210
from flpbalada/my-opencode-config

Guides TypeScript best practices for type safety, code organization, and maintainability. Use this skill when configuring TypeScript projects, deciding on typing strategies, writing async code, or reviewing TypeScript code quality.