.config/opencode/skills/react-use-state/SKILL.md
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.
npx skillsauth add klen/dotfiles react-use-stateInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
useState is a React Hook that adds a state variable to your component,
triggering re-renders when the state changes.
const [state, setState] = useState(initialState);
| 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([]) |
When you need mutable values that don't trigger re-renders:
// Interval IDs, DOM references, previous values
const intervalRef = useRef(null);
const inputRef = useRef(null);
When state logic is complex:
// Multiple related values, complex transitions
const [state, dispatch] = useReducer(reducer, initialState);
Use useReducer when:
If a value can be computed from props or other state, don't store it:
// 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]
);
For state shared across multiple components:
// 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]);
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
}
// 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
}
// 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));
// 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
}
// Parent controls reset via key
<Form key={version} />
// When version changes, Form remounts with fresh state
// BAD: Function gets called
const [fn, setFn] = useState(someFunction);
// GOOD: Wrap in arrow function
const [fn, setFn] = useState(() => someFunction);
setFn(() => newFunction);
// 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
setState unconditionally during render| 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 |
tools
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.
development
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.
development
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.
development
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.