component-refactoring
Skill8 starsChanged 3 months agoMITView on GitHub
Refactor high-complexity React components in Langflow frontend. Use when manual complexity assessment shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.
5 other projects use a version of this, 4 of them edited.
Adopted by
Most recently taken up by
- Ohh-889/skyroc-adminedited, first seen Oct 8, 2026
- langflow-ai/langflowword for word, first seen Oct 8, 2026
- factor241/ketos-botedited, first seen Sep 3, 2026
- jpoindexter/theft-kitedited, first seen May 20, 2026
- Charlie85270/Dorothyedited, first seen Jan 27, 2026
Other versions5 projects use a version of this.
Word for word · 1
- langflow-ai/langflow★ 156k100% same
Edited · 4
- Ohh-889/skyroc-admin★ 79527% same
- Charlie85270/Dorothy★ 35327% same
- factor241/ketos-bot★ 194% same
- jpoindexter/theft-kit★ 130% same
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository13 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/docs_development.mdcCursor rule
- backend-code-reviewSkill
- e2e-testingSkill
- frontend-code-reviewSkill
- frontend-i18nSkill
- frontend-query-mutationSkill
- frontend-testingSkill
- ibm-a11y-level1-auditSkill
- ibm-a11y-pr-remediationSkill
- ibm-a11y-route-scanSkill
- ibm-a11y-testing-guideSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
21 rules. 3 are common, 5 are distinctive, and 13 are very specific to this project.
3
Common
Most of the 4 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 54
Langflow Convention: Place hooks in a hooks/ subdirectory or alongside the component as use-<feature>.ts.
- Very specific: line 96
Langflow Convention: Place sub-components in subdirectories or as separate files in the same directory.
- Very specific: line 195
When refactoring data fetching, use frontend-query-mutation for query patterns, UseRequestProcessor, cache invalidation, and mutation error …
- Very specific: line 196
Do not create thin passthrough useQuery wrappers during refactoring.
- Very specific: line 289
Langflow Reference: All stores in src/frontend/src/stores/ follow this selector pattern.
- Distinctive: line 296
Keep node logic in custom hooks
- Very specific: line 298
Use the existing components/ subdirectory for sub-components
- Distinctive: line 318
Keep canvas event handlers separate from UI rendering
- Very specific: line 319
Use useFlowStore for flow state management
- Very specific: line 320
Use useFlowsManagerStore for multi-flow management
- Very specific: line 327
Use existing query hooks from controllers/API/queries/
- Very specific: line 329
Use query key arrays like ["useGetGlobalVariables"] for cache management
- Common: line 345
Create a refactoring plan based on detected features:
- Distinctive: line 375
After refactoring, re-assess complexity manually:
- Very specific: line 403
Follow existing directory structures in components/ui/, components/core/, components/common/
- Distinctive: line 406
Keep Zustand store selector patterns consistent
- Common: line 410
Only extract when there is clear complexity benefit
- Distinctive: line 411
Do not create abstractions for single-use code
- Common: line 412
Keep refactored code in the same domain area
- Very specific: line 416
Do not call useQuery or useMutation directly for API calls
- Very specific: line 417
Always use the UseRequestProcessor pattern for consistency with retry and invalidation logic
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Langflow Component Refactoring Skill
Refactor high-complexity React components in the Langflow frontend codebase with the patterns and workflow below.
Complexity Threshold: Components with complexity > 50 (measured manually by counting conditionals, nesting levels, and lines) should be refactored before testing.
Quick Reference
Commands (run from src/frontend/)
cd src/frontend
# Lint with Biome
npm run lint
# Type checking
npm run type-check
# Run tests
npm testManual Complexity Assessment
Since Langflow does not have automated complexity analysis tools, assess components manually:
- Count conditionals: Each
if/else,switch/case, ternary,&&/||chain adds +1. - Count nesting levels: Each level of nesting within conditionals or loops adds +1.
- Count total lines: Target < 300 lines per component file.
- Count state hooks: More than 5
useStatecalls suggests hook extraction. - Count effects: More than 3
useEffectcalls suggests effect consolidation.
Complexity Score Interpretation
| Score | Level | Action |
| 0-25 | Simple | Ready for testing |
| 26-50 | Medium | Consider minor refactoring |
| 51-75 | Complex | Refactor before testing |
| 76-100 | Very Complex | Must refactor |
Core Refactoring Patterns
Pattern 1: Extract Custom Hooks
When: Component has complex state management, multiple useState/useEffect, or business logic mixed with UI.
Langflow Convention: Place hooks in a hooks/ subdirectory or alongside the component as use-<feature>.ts. Langflow uses kebab-case filenames with use- prefix.
// Before: Complex state logic in component
const FlowPage: FC = () => {
const [nodes, setNodes] = useState<Node[]>([])
const [edges, setEdges] = useState<Edge[]>([])
const [buildStatus, setBuildStatus] = useState<BuildStatus>(BuildStatus.IDLE)
// 50+ lines of state management logic...
return <div>...</div>
}
// After: Extract to custom hook
// hooks/use-flow-state.ts
export const useFlowState = (flowId: string) => {
const [nodes, setNodes] = useState<Node[]>([])
const [edges, setEdges] = useState<Edge[]>([])
const [buildStatus, setBuildStatus] = useState<BuildStatus>(BuildStatus.IDLE)
// Related state management logic here
return { nodes, setNodes, edges, setEdges, buildStatus, setBuildStatus }
}
// Component becomes cleaner
const FlowPage: FC = () => {
const { nodes, setNodes, edges, setEdges } = useFlowState(flowId)
return <div>...</div>
}Langflow Examples:
src/frontend/src/hooks/use-add-component.tssrc/frontend/src/hooks/use-unsaved-changes.tssrc/frontend/src/hooks/use-refresh-model-inputs.ts
Pattern 2: Extract Sub-Components
When: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.
Langflow Convention: Place sub-components in subdirectories or as separate files in the same directory. UI primitives go in components/ui/, domain components in components/core/, reusable components in components/common/.
// Before: Monolithic JSX with multiple sections
const GenericNode = () => {
return (
<div>
{/* 100 lines of header UI */}
{/* 100 lines of parameter fields */}
{/* 100 lines of output handles */}
</div>
)
}
// After: Split into focused components
// CustomNodes/GenericNode/
// generic-node.tsx (orchestration only — kebab-case, descriptive name)
// components/
// node-header.tsx
// node-parameters.tsx
// node-outputs.tsx
const GenericNode = () => {
return (
<div>
<NodeHeader nodeData={data} />
<NodeParameters fields={fields} />
<NodeOutputs outputs={outputs} />
</div>
)
}Langflow Examples:
src/frontend/src/CustomNodes/GenericNode/components/src/frontend/src/components/core/src/frontend/src/components/ui/
Pattern 3: Simplify Conditional Logic
When: Deep nesting (> 3 levels), complex ternaries, or multiple if/else chains.
// Before: Deeply nested conditionals
const getFieldComponent = (field: InputFieldType) => {
if (field.type === "str") {
if (field.multiline) {
return <TextAreaComponent />
} else if (field.password) {
return <PasswordInput />
} else if (field.options?.length) {
return <Dropdown options={field.options} />
} else {
return <InputComponent />
}
} else if (field.type === "int") {
return <IntComponent />
} else if (field.type === "float") {
return <FloatComponent />
}
return null
}
// After: Use lookup tables + early returns
const FIELD_COMPONENT_MAP: Record<string, FC<FieldProps>> = {
int: IntComponent,
float: FloatComponent,
bool: ToggleComponent,
code: CodeAreaComponent,
}
const STR_VARIANT_MAP: Record<string, FC<FieldProps>> = {
multiline: TextAreaComponent,
password: PasswordInput,
options: Dropdown,
}
const getFieldComponent = (field: InputFieldType) => {
if (field.type !== "str") {
const Component = FIELD_COMPONENT_MAP[field.type]
return Component ? <Component {...field} /> : null
}
const variant = field.multiline ? "multiline"
: field.password ? "password"
: field.options?.length ? "options"
: "default"
const Component = STR_VARIANT_MAP[variant] ?? InputComponent
return <Component {...field} />
}Pattern 4: Extract API/Data Logic
When: Component directly handles API calls, data transformation, or complex async operations.
Langflow Convention:
- This skill is for component decomposition, not query/mutation design.
- When refactoring data fetching, use
frontend-query-mutationfor query patterns,UseRequestProcessor, cache invalidation, and mutation error handling. - Do not create thin passthrough
useQuerywrappers during refactoring; only extract a custom hook when it truly orchestrates multiple queries/mutations or shared derived state. - API hooks live in
controllers/API/queries/{domain}/.
Langflow Examples:
src/frontend/src/controllers/API/queries/flows/use-post-add-flow.tssrc/frontend/src/controllers/API/queries/variables/use-get-global-variables.tssrc/frontend/src/controllers/API/queries/folders/use-get-folders.ts
Pattern 5: Extract Modal/Dialog Management
When: Component manages multiple modals with complex open/close states.
Langflow Convention: Modals should be extracted with their state management.
// Before: Multiple modal states in component
const FlowToolbar = () => {
const [showExportModal, setShowExportModal] = useState(false)
const [showShareModal, setShowShareModal] = useState(false)
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
const [showApiModal, setShowApiModal] = useState(false)
// 5+ more modal states...
}
// After: Extract to modal management hook
type ModalType = "export" | "share" | "delete" | "api" | null
const useFlowToolbarModals = () => {
const [activeModal, setActiveModal] = useState<ModalType>(null)
const openModal = useCallback((type: ModalType) => setActiveModal(type), [])
const closeModal = useCallback(() => setActiveModal(null), [])
return {
activeModal,
openModal,
closeModal,
isOpen: (type: ModalType) => activeModal === type,
}
}Pattern 6: Extract Form Logic
When: Complex form validation, submission handling, or field transformation.
Langflow Convention: Extract form state and validation into hooks.
// Extract form validation and submission
const useFlowSettingsForm = (initialValues: FlowSettings) => {
const [values, setValues] = useState(initialValues)
const [errors, setErrors] = useState<Record<string, string>>({})
const validate = useCallback(() => {
const newErrors: Record<string, string> = {}
if (!values.name?.trim()) newErrors.name = "Name is required"
if (values.endpoint_name && !/^[a-z0-9-]+$/.test(values.endpoint_name)) {
newErrors.endpoint_name = "Must be lowercase alphanumeric with hyphens"
}
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}, [values])
const handleChange = useCallback((field: string, value: any) => {
setValues((prev) => ({ ...prev, [field]: value }))
}, [])
return { values, errors, validate, handleChange }
}Langflow-Specific Refactoring Guidelines
1. Zustand Store Selectors
When: Component reads many values from a Zustand store, causing unnecessary re-renders.
// Before: Selecting too many values
const Component = () => {
const flowStore = useFlowStore()
// Component re-renders on ANY store change
}
// After: Use individual selectors
const Component = () => {
const nodes = useFlowStore((state) => state.nodes)
const edges = useFlowStore((state) => state.edges)
// Component only re-renders when nodes or edges change
}Langflow Reference: All stores in src/frontend/src/stores/ follow this selector pattern.
2. Custom Node Components
When: Refactoring flow node components (CustomNodes/GenericNode/).
Conventions:
- Keep node logic in custom hooks
- Extract parameter rendering to separate components
- Use the existing
components/subdirectory for sub-components
CustomNodes/GenericNode/
generic-node.tsx # Node registration and main render (kebab-case, NOT index.tsx)
components/
handle-render.tsx # Handle rendering
node-description.tsx # Node description display
node-input-field.tsx # Input field rendering
node-name.tsx # Node name display
node-output-field.tsx # Output field rendering
node-status.tsx # Build status display3. Flow Canvas Components
When: Refactoring components related to the flow editor canvas.
Conventions:
@xyflow/reactv12 is the canvas library- Keep canvas event handlers separate from UI rendering
- Use
useFlowStorefor flow state management - Use
useFlowsManagerStorefor multi-flow management
4. API Query Hook Components
When: Refactoring components that consume API data.
Conventions:
- Use existing query hooks from
controllers/API/queries/ - Access
UseRequestProcessorfor new queries/mutations - Use query key arrays like
["useGetGlobalVariables"]for cache management - Cache invalidation belongs in mutation
onSettledcallbacks
Refactoring Workflow
Step 1: Assess Complexity
Manually count:
- Total conditionals (if/else, switch, ternary, &&/||)
- Maximum nesting depth
- Total lines of code
- Number of useState/useEffect hooks
- Number of distinct UI sections
Step 2: Plan
Create a refactoring plan based on detected features:
| Detected Feature | Refactoring Action |
5+ useState hooks with related state | Extract custom hook |
| API calls in component body | Extract to query hook |
| 3+ event handlers with logic | Extract event handlers to hook |
| 300+ lines | Split into sub-components |
| Deep conditional nesting (>3) | Simplify conditional logic |
| Multiple modal states | Extract modal management |
Step 3: Execute Incrementally
- Extract one piece at a time
- Run lint, type-check, and tests after each extraction
- Verify functionality before next step
For each extraction:
1. Extract code
2. Run: npm run lint
3. Run: npm run type-check
4. Run: npm test
5. Test functionality manually
6. PASS? -> Next extraction
FAIL? -> Fix before continuingStep 4: Verify
After refactoring, re-assess complexity manually:
- Target complexity < 50
- Target line count < 300
- Target max nesting depth <= 3
- Target max function length < 30 lines
Common Mistakes to Avoid
Over-Engineering
// Too many tiny hooks
const useButtonText = () => useState("Click")
const useButtonDisabled = () => useState(false)
const useButtonLoading = () => useState(false)
// Cohesive hook with related state
const useButtonState = () => {
const [text, setText] = useState("Click")
const [disabled, setDisabled] = useState(false)
const [loading, setLoading] = useState(false)
return { text, setText, disabled, setDisabled, loading, setLoading }
}Breaking Existing Patterns
- Follow existing directory structures in
components/ui/,components/core/,components/common/ - Maintain naming conventions (kebab-case files, PascalCase components)
- Preserve export patterns for compatibility
- Keep Zustand store selector patterns consistent
Premature Abstraction
- Only extract when there is clear complexity benefit
- Do not create abstractions for single-use code
- Keep refactored code in the same domain area
Bypassing UseRequestProcessor
- Do not call
useQueryoruseMutationdirectly for API calls - Always use the
UseRequestProcessorpattern for consistency with retry and invalidation logic - See
frontend-query-mutationskill for API hook patterns
References
Langflow Codebase Examples
- Hook extraction:
src/frontend/src/hooks/ - Component splitting:
src/frontend/src/CustomNodes/GenericNode/components/ - UI components:
src/frontend/src/components/ui/ - Core components:
src/frontend/src/components/core/ - Common components:
src/frontend/src/components/common/ - API query hooks:
src/frontend/src/controllers/API/queries/ - Zustand stores:
src/frontend/src/stores/
Related Skills
frontend-query-mutation- For API query and mutation patternsfrontend-testing- For testing refactored components
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.

