Documentation Index
Fetch the complete documentation index at: https://codegeninc-fix-system-prompt-typo.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Codegen SDK provides powerful APIs for modernizing React codebases. This guide will walk you through common React modernization patterns.
Common use cases include:
- Upgrading to modern APIs, including React 18+
- Automatically memoizing components
- Converting to modern hooks
- Standardizing prop types
- Organizing components into individual files
and much more.
Converting Class Components to Functions
Here’s how to convert React class components to functional components:
# Find all React class components
for class_def in codebase.classes:
# Skip if not a React component
if not class_def.is_jsx or "Component" not in [base.name for base in class_def.bases]:
continue
print(f"Converting {class_def.name} to functional component")
# Extract state from constructor
constructor = class_def.get_method("constructor")
state_properties = []
if constructor:
for statement in constructor.code_block.statements:
if "this.state" in statement.source:
# Extract state properties
state_properties = [prop.strip() for prop in
statement.source.split("{")[1].split("}")[0].split(",")]
# Create useState hooks for each state property
state_hooks = []
for prop in state_properties:
hook_name = f"[{prop}, set{prop[0].upper()}{prop[1:]}]"
state_hooks.append(f"const {hook_name} = useState(null);")
# Convert lifecycle methods to effects
effects = []
if class_def.get_method("componentDidMount"):
effects.append("""
useEffect(() => {
// TODO: Move componentDidMount logic here
}, []);
""")
if class_def.get_method("componentDidUpdate"):
effects.append("""
useEffect(() => {
// TODO: Move componentDidUpdate logic here
});
""")
# Get the render method
render_method = class_def.get_method("render")
# Create the functional component
func_component = f"""
const {class_def.name} = ({class_def.get_method("render").parameters[0].name}) => {{
{chr(10).join(state_hooks)}
{chr(10).join(effects)}
{render_method.code_block.source}
}}
"""
# Replace the class with the functional component
class_def.edit(func_component)
# Add required imports
file = class_def.file
if not any("useState" in imp.source for imp in file.imports):
file.add_import("import { useState, useEffect } from 'react';")
Migrating to Modern Hooks
Convert legacy patterns to modern React hooks:
# Find components using legacy patterns
for function in codebase.functions:
if not function.is_jsx:
continue
# Look for common legacy patterns
for call in function.function_calls:
# Convert withRouter to useNavigate
if call.name == "withRouter":
# Add useNavigate import
function.file.add_import(
"import { useNavigate } from 'react-router-dom';"
)
# Add navigate hook
function.insert_before_first_return("const navigate = useNavigate();")
# Replace history.push calls
for history_call in function.function_calls:
if "history.push" in history_call.source:
history_call.edit(
history_call.source.replace("history.push", "navigate")
)
# Convert lifecycle methods in hooks
elif call.name == "componentDidMount":
call.parent.edit("""
useEffect(() => {
// Your componentDidMount logic here
}, []);
""")
Standardizing Props
Inferring Props from Usage
Add proper prop types and TypeScript interfaces based on how props are used:
# Add TypeScript interfaces for props
for function in codebase.functions:
if not function.is_jsx:
continue
# Get props parameter
props_param = function.parameters[0] if function.parameters else None
if not props_param:
continue
# Collect used props
used_props = set()
for prop_access in function.function_calls:
if f"{props_param.name}." in prop_access.source:
prop_name = prop_access.source.split(".")[1]
used_props.add(prop_name)
# Create interface
if used_props:
interface_def = f"""
interface {function.name}Props {{
{chr(10).join(f' {prop}: any;' for prop in used_props)}
}}
"""
function.insert_before(interface_def)
# Update function signature
function.edit(function.source.replace(
f"({props_param.name})",
f"({props_param.name}: {function.name}Props)"
))
Convert inline prop type definitions to separate type declarations:
# Iterate over all files in the codebase
for file in codebase.files:
# Iterate over all functions in the file
for function in file.functions:
# Check if the function is a React functional component
if function.is_jsx: # Assuming is_jsx indicates a function component
# Check if the function has inline props definition
if len(function.parameters) == 1 and isinstance(function.parameters[0].type, Dict):
# Extract the inline prop type
inline_props: TSObjectType = function.parameters[0].type.source
# Create a new type definition for the props
props_type_name = f"{function.name}Props"
props_type_definition = f"type {props_type_name} = {inline_props};"
# Set the new type for the parameter
function.parameters[0].set_type_annotation(props_type_name)
# Add the new type definition to the file
function.insert_before('\n' + props_type_definition + '\n')
This will convert components from:
function UserCard({ name, age }: { name: string; age: number }) {
return (
<div>
{name} ({age})
</div>
);
}
To:
type UserCardProps = { name: string; age: number };
function UserCard({ name, age }: UserCardProps) {
return (
<div>
{name} ({age})
</div>
);
}
Extracting prop types makes them reusable and easier to maintain. It also
improves code readability by separating type definitions from component logic.
Updating Fragment Syntax
Modernize React Fragment syntax:
for function in codebase.functions:
if not function.is_jsx:
continue
# Replace React.Fragment with <>
for element in function.jsx_elements:
if element.name == "React.Fragment":
element.edit(element.source.replace(
"<React.Fragment>",
"<>"
).replace(
"</React.Fragment>",
"</>"
))
Organizing Components into Individual Files
A common modernization task is splitting files with multiple components into a more maintainable structure where each component has its own file. This is especially useful when modernizing legacy React codebases that might have grown organically.
# Initialize a dictionary to store files and their corresponding JSX components
files_with_jsx_components = {}
# Iterate through all files in the codebase
for file in codebase.files:
# Check if the file is in the components directory
if 'components' not in file.filepath:
continue
# Count the number of JSX components in the file
jsx_count = sum(1 for function in file.functions if function.is_jsx)
# Only proceed if there are multiple JSX components
if jsx_count > 1:
# Identify non-default exported components
non_default_components = [
func for func in file.functions
if func.is_jsx and not func.is_exported
]
default_components = [
func for func in file.functions
if func.is_jsx and func.is_exported and func.export.is_default_export()
]
# Log the file path and its components
print(f"📁 {file.filepath}:")
for component in default_components:
print(f" 🟢 {component.name} (default)")
for component in non_default_components:
print(f" 🔵 {component.name}")
# Create a new directory path based on the original file's directory
new_dir_path = "/".join(file.filepath.split("/")[:-1]) + "/" + file.name.split(".")[0]
codebase.create_directory(new_dir_path, exist_ok=True)
# Create a new file path for the component
new_file_path = f"{new_dir_path}/{component.name}.tsx"
new_file = codebase.create_file(new_file_path)
# Log the movement of the component
print(f" 🫸 Moved to: {new_file_path}")
# Move the component to the new file
component.move_to_file(new_file, strategy="add_back_edge")
This script will:
- Find files containing multiple React components
- Create a new directory structure based on the original file
- Move each non-default exported component to its own file
- Preserve imports and dependencies automatically
- Keep default exports in their original location
For example, given this structure:
components/
Forms.tsx # Contains Button, Input, Form (default)
It will create:
components/
Forms.tsx # Contains Form (default)
forms/
Button.tsx
Input.tsx
The strategy="add_back_edge" parameter ensures that any components that were
previously co-located can still import each other without circular
dependencies. Learn more about moving
code here.