nested-component-fix
Detects and fixes React components defined inside other components — hoists inner components to module level to preserve state and avoid unnecessary re-creation on every render.
Problem
Defining a component inside another component's body creates a new function reference on each render. That:
- Destroys component state on every parent re-render
- Hurts performance
- Can cause infinite re-render loops
Solution
The codemod hoists inner component definitions to the module level so they stay stable across renders.
Usage
bash
Branch creation (on by default): Use --param create_branch=false to skip creating a branch. When on, a branch is created first and commits are made after each step.
Publish branch (always runs last): Pushes the local branch to remote.
Create PR (off by default): Use --param publish_pr=true to create a PR targeting the main branch. Requires gh CLI (or --param api_token=<token> for GitHub API). Optional params: main_branch (default: main), pr_title, pr_body.
Metrics
- effort-automated: Cases fixed by the AST codemod (no closure over outer scope)
- effort-remained: Tricky cases skipped (closure over outer scope, etc.) — use the optional AI step for these
Cardinalities (for aggregation):
- change_type: automated-by-codemod | to-be-done-by-ai-or-human
- change_difficulty_category: simple | complex (closure refactors are complex; malformed-declaration is simple)
Create PR (Optional, runs last)
Run with --param publish_pr=true to create a PR after pushing the branch. The workflow first pushes the branch to remote, then optionally creates a PR. Requires gh CLI or api_token for GitHub API. Off by default. Optional params: main_branch (default: main), pr_title, pr_body, api_token (for CI/automation).
Tricky Cases (Optional AI Step)
Run with --param run_ai_step=true to fix cases the codemod skips:
- Inner component uses variables from outer scope (closure) — refactor to pass as props
- Complex nesting (A inside B inside C)
- Conditionally defined components
What Gets Fixed
Automated (no AI):
- const Inner = () => <div>...</div> inside a component
- Inner component used as <Inner /> or <Inner>...</Inner>
- No closure over outer scope
Skipped (effort-remained, use AI step):
- Inner component references outer scope (useState, props, local vars)
- Conditionally defined components