class-to-function-component
Transform React class components to modern function components
# Class-to-Function Component Codemod
š **Transform React class components to modern functional components with hooks**
This repository contains a powerful codemod that automatically converts React class components to functional components, handling complex transformations including state management, lifecycle methods, refs, and context usage.
## ⨠Features
- **Complete class-to-function transformation** - Converts `React.Component` and `React.PureComponent` to functional components
- **Smart state management** - Transforms `this.state` and `this.setState` to `useState` hooks
- **Lifecycle method conversion** - Converts `componentDidMount`, `componentDidUpdate`, etc. to `useEffect` hooks
- **Ref handling** - Transforms `createRef` and `this.refName` to `useRef` hooks
- **Context integration** - Converts `this.context` to `useContext` hooks
- **Event handler optimization** - Transforms class methods to optimized event handlers
- **Optional AI Review** - AI-powered code review and fixes (requires OpenAI API key)
- **TypeScript support** - Full TypeScript type preservation and enhancement
## š Quick Start
### Basic Usage (No AI Required)
```bash
# Transform all JavaScript/TypeScript files in your project
npx codemod@latest workflow run --workflow workflow.yaml
# Transform specific directory
npx codemod@latest workflow run --workflow workflow.yaml --target src/components
# Preview changes without applying them
npx codemod@latest workflow run --workflow workflow.yaml --dry-run
```
### AI-Enhanced Usage (Optional)
```bash
# Set your OpenAI API key
export LLM_API_KEY="your-openai-api-key"
# Run with AI review for better results
npx codemod@latest workflow run --workflow workflow.yaml --param autoAiReview=true
```
## š Detailed Usage
### Command Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--param autoAiReview=true` | boolean | `false` | Enable AI code review (requires `LLM_API_KEY`) |
| `--target <PATH>` | string | current directory | Directory to transform |
| `--dry-run` | boolean | `false` | Preview changes without applying |
| `--verbose` | boolean | `false` | Show detailed output |
### Examples
#### Example 1: Simple Counter Component
**Before:**
```tsx
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
componentDidMount() {
console.log('Counter mounted');
}
increment = () => {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<div>
<h2>Count: {this.state.count}</h2>
<button onClick={this.increment}>+</button>
</div>
);
}
}
```
**After:**
```tsx
import React from 'react';
function Counter() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log('Counter mounted');
}, []);
const increment = () => {
setCount(prevCount => prevCount + 1);
}
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increment}>+</button>
</div>
);
}
```
#### Example 2: Component with Context and Refs
**Before:**
```tsx
import React, { Component, createRef } from 'react';
import { UserContext } from './UserContext';
class UserProfile extends Component {
static contextType = UserContext;
private inputRef = createRef<HTMLInputElement>();
componentDidMount() {
this.inputRef.current?.focus();
}
handleSubmit = () => {
const user = this.context;
console.log('User:', user);
}
render() {
const user = this.context;
return (
<form>
<input ref={this.inputRef} defaultValue={user.name} />
<button onClick={this.handleSubmit}>Save</button>
</form>
);
}
}
```
**After:**
```tsx
import React, { useRef, useContext } from 'react';
import { UserContext } from './UserContext';
function UserProfile() {
const user = useContext(UserContext);
const inputRef = useRef<HTMLInputElement>(null);
React.useEffect(() => {
inputRef.current?.focus();
}, []);
const handleSubmit = () => {
console.log('User:', user);
}
return (
<form>
<input ref={inputRef} defaultValue={user.name} />
<button onClick={handleSubmit}>Save</button>
</form>
);
}
```
## AI Review Features
When you enable AI review with `--autoAiReview=true`, the AI will:
- ā
**Fix dependency arrays** in useEffect hooks
- ā
**Optimize event handlers** with useCallback
- ā
**Add missing dependencies** to prevent stale closures
- ā
**Improve performance** with useMemo where appropriate
- ā
**Fix TypeScript types** and add proper type annotations
- ā
**Format code** according to best practices
- ā
**Detect and fix** common React patterns
### Setting up AI Review
1. **Get an OpenAI API Key:**
- Visit [OpenAI Platform](https://platform.openai.com/api-keys)
- Create a new API key
- Copy the key
2. **Set Environment Variable:**
```bash
# Linux/Mac
export LLM_API_KEY="sk-your-api-key-here"
# Windows (PowerShell)
$env:LLM_API_KEY="sk-your-api-key-here"
# Windows (Command Prompt)
set LLM_API_KEY=sk-your-api-key-here
```
3. **Run with AI:**
```bash
npx codemod@latest workflow run --workflow workflow.yaml --param autoAiReview=true
```
## š ļø Development
```bash
# Clone and setup
git clone <repository-url>
cd class-to-function-component
npm install
# Test the transformation
npm test
# Validate the workflow
npx codemod@latest workflow validate workflow.yaml
# Run locally
npx codemod@latest workflow run --workflow workflow.yaml
```
## š Troubleshooting
### Common Issues
**"No files found to transform"**
```bash
# Check if files match the pattern
npx codemod@latest workflow run --workflow workflow.yaml --dry-run --verbose
# Use specific target directory
npx codemod@latest workflow run --workflow workflow.yaml --target src
```
**"AI review failed"**
```bash
# Check API key is set
echo $LLM_API_KEY
# Run without AI review (default behavior)
npx codemod@latest workflow run --workflow workflow.yaml
```
**TypeScript compilation errors**
```bash
# Use AI review to fix types
npx codemod@latest workflow run --workflow workflow.yaml --param autoAiReview=true
# Check TypeScript version
npx tsc --version
```
## More Examples
For more detailed examples and advanced usage patterns, see [USAGE.md](./USAGE.md).
## Contributing
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## š License
MIT License - see [LICENSE](LICENSE) file for details.