class-to-hooks
Skill4 starsChanged 8 months agoMITView on GitHub
Convert React class components to modern functional components with hooks while preserving all behavior, lifecycle logic, and edge cases. Use it when modernizing a React codebase that uses class components; when a class component needs new features that are easier to implement with hooks; when you want to reduce bundle size (functional components are smaller); when preparing for concurrent React features that work better with functional components.
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 7 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 17
If multiple state values always change together, keep them in a single useState with an object
- Very specific: line 18
If state updates depend on previous state, always use the functional form: setState(prev => ...)
- Very specific: line 50
Only use useCallback when the function is passed to a memoized child component or used as a useEffect dependency.
- Distinctive: line 59
If the component is an error boundary, either keep it as a class or extract the error boundary into a separate class wrapper and convert …
- Very specific: line 69
If the class component has methods called by parent via ref, use useImperativeHandle
- Distinctive: line 72
Do NOT change the component's external API (props, ref interface, context)
- Distinctive: line 73
Do NOT combine unrelated state into one useState call
- Distinctive: line 74
Do NOT add unnecessary useMemo or useCallback (premature optimization)
- Distinctive: line 75
Do NOT change the rendering logic or JSX structure
- Distinctive: line 76
Do NOT fix bugs during migration (note them as TODOs instead)
- Distinctive: line 77
Do NOT change the file's export pattern (default vs.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- Generated from recipes/migrations/class-to-hooks.md by scripts/build-skills.sh. Edit the recipe, then rerun the script. -->React Class Components to Hooks Migration
You are a React migration expert. Convert the provided React class component(s) to functional components with hooks. The converted component must be behaviorally identical to the original, including all lifecycle timing, error handling, and edge cases.
CONVERSION RULES
State
this.state = { ... }->useState()for each independent piece of state- If multiple state values always change together, keep them in a single
useStatewith an object - If state updates depend on previous state, always use the functional form:
setState(prev => ...) this.setStatecallback (second argument) -> useuseEffectthat depends on the state value
Lifecycle Methods
| Class Method | Hooks Equivalent |
constructor | useState initial values + top-level statements |
componentDidMount | useEffect(() => { ... }, []) |
componentDidUpdate | useEffect(() => { ... }, [deps]) or useEffect(() => { ... }) |
componentWillUnmount | useEffect(() => { return () => cleanup }, []) |
shouldComponentUpdate | React.memo() wrapper with custom comparison |
getDerivedStateFromProps | Compute during render (variable assignment) or useState + update in render |
getSnapshotBeforeUpdate | useRef + useLayoutEffect (rare, flag if needed) |
componentDidCatch | Keep as class component (error boundaries require classes) OR use a library like react-error-boundary |
Refs
createRef()->useRef()- Callback refs ->
useCallbackref pattern - String refs (legacy) ->
useRef() this.myRef.current->myRef.current(no change in access pattern)
Instance Variables (non-state, non-ref)
this.intervalId,this.abortController, etc. ->useRef()(mutable ref that doesn't trigger re-renders)- These are NOT state because changing them should NOT cause a re-render
Context
static contextType = MyContext->useContext(MyContext)- Multiple contexts: nest
useContextcalls (no need for nested Consumer components)
Event Handlers
- Class methods -> functions defined inside the component or wrapped in
useCallbackif passed as props to child components - Only use
useCallbackwhen the function is passed to a memoized child component or used as auseEffectdependency. Don't wrap every handler in useCallback
Performance
PureComponent->React.memo(Component)shouldComponentUpdate(nextProps, nextState)->React.memo(Component, (prevProps, nextProps) => { ... })(note: return true to SKIP re-render, opposite of shouldComponentUpdate)- Expensive calculations in render ->
useMemo(() => compute(deps), [deps])
Error Boundaries
- Error boundaries CANNOT be converted to functional components (React limitation as of React 18)
- If the component is an error boundary, either keep it as a class or extract the error boundary into a separate class wrapper and convert only the rendering logic to a functional component
- Alternatively, suggest using the
react-error-boundarylibrary
IMPORTANT: Preserve These Behaviors
- Preserve the exact same props interface (don't rename or restructure props)
- Preserve forwardRef if the component accepts refs
- Preserve displayName if set
- Preserve default props (convert static defaultProps to default parameter values)
- Preserve the component's position in the render tree (don't wrap in extra divs)
- Preserve all event handler behavior and side effects
- If the class component has methods called by parent via ref, use
useImperativeHandle
What NOT to Do
- Do NOT change the component's external API (props, ref interface, context)
- Do NOT combine unrelated state into one useState call
- Do NOT add unnecessary useMemo or useCallback (premature optimization)
- Do NOT change the rendering logic or JSX structure
- Do NOT fix bugs during migration (note them as TODOs instead)
- Do NOT change the file's export pattern (default vs. named)
OUTPUT FORMAT
Provide:
- The complete converted functional component
- A migration notes section listing:
- Each lifecycle method and its hooks equivalent
- Any behavioral nuances to verify in testing
- Any changes that couldn't be made (e.g., error boundaries)
- Suggested follow-up refactors (but not done in this migration)
The source recipe, with a worked example and customization tips, is https://github.com/Sagargupta16/agent-recipes/blob/main/recipes/migrations/class-to-hooks.md
In this repository22 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- api-docs-generatorSkill
- architecture-reviewSkill
- background-deploy-monitorSkill
- changelog-writerSkill
- ci-cd-pipelineSkill
- cjs-to-esmSkill
- coverage-gap-finderSkill
- dependency-auditSkill
- dockerfile-generatorSkill
- e2e-test-writerSkill
- generate-unit-testsSkill
- input-validationSkill
- js-to-tsSkill
- monitoring-setupSkill
- multi-repo-pr-checkSkill
- owasp-auditSkill
- performance-reviewSkill
- pr-reviewSkill
- readme-generatorSkill
- secret-scannerSkill
- upgrade-dependenciesSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

