React Modernization
Upgrade React apps to latest versions with automated hooks migration
✨ The solution you've been looking for
Upgrade React applications to latest versions, migrate from class components to hooks, and adopt concurrent features. Use when modernizing React codebases, migrating to React Hooks, or upgrading to latest React versions.
See It In Action
Interactive preview & real-world examples
AI Conversation Simulator
See how users interact with this skill
User Prompt
I have a React class component with state and lifecycle methods. Help me migrate it to use hooks while maintaining the same functionality.
Skill Processing
Analyzing request...
Agent Response
Step-by-step migration guide with before/after code examples, proper hook usage patterns, and testing recommendations
Quick Start (3 Steps)
Get up and running in minutes
Install
claude-code skill install react-modernization
claude-code skill install react-modernizationConfig
First Trigger
@react-modernization helpCommands
| Command | Description | Required Args |
|---|---|---|
| @react-modernization legacy-class-component-migration | Convert existing React class components to modern functional components with hooks | None |
| @react-modernization react-18-upgrade-path | Upgrade from React 16/17 to React 18 with concurrent features adoption | None |
| @react-modernization automated-codemod-application | Use codemods to automatically refactor large codebases during React upgrades | None |
Typical Use Cases
Legacy Class Component Migration
Convert existing React class components to modern functional components with hooks
React 18 Upgrade Path
Upgrade from React 16/17 to React 18 with concurrent features adoption
Automated Codemod Application
Use codemods to automatically refactor large codebases during React upgrades
Overview
React Modernization
Master React version upgrades, class to hooks migration, concurrent features adoption, and codemods for automated transformation.
When to Use This Skill
- Upgrading React applications to latest versions
- Migrating class components to functional components with hooks
- Adopting concurrent React features (Suspense, transitions)
- Applying codemods for automated refactoring
- Modernizing state management patterns
- Updating to TypeScript
- Improving performance with React 18+ features
Version Upgrade Path
React 16 → 17 → 18
Breaking Changes by Version:
React 17:
- Event delegation changes
- No event pooling
- Effect cleanup timing
- JSX transform (no React import needed)
React 18:
- Automatic batching
- Concurrent rendering
- Strict Mode changes (double invocation)
- New root API
- Suspense on server
Class to Hooks Migration
State Management
1// Before: Class component
2class Counter extends React.Component {
3 constructor(props) {
4 super(props);
5 this.state = {
6 count: 0,
7 name: "",
8 };
9 }
10
11 increment = () => {
12 this.setState({ count: this.state.count + 1 });
13 };
14
15 render() {
16 return (
17 <div>
18 <p>Count: {this.state.count}</p>
19 <button onClick={this.increment}>Increment</button>
20 </div>
21 );
22 }
23}
24
25// After: Functional component with hooks
26function Counter() {
27 const [count, setCount] = useState(0);
28 const [name, setName] = useState("");
29
30 const increment = () => {
31 setCount(count + 1);
32 };
33
34 return (
35 <div>
36 <p>Count: {count}</p>
37 <button onClick={increment}>Increment</button>
38 </div>
39 );
40}
Lifecycle Methods to Hooks
1// Before: Lifecycle methods
2class DataFetcher extends React.Component {
3 state = { data: null, loading: true };
4
5 componentDidMount() {
6 this.fetchData();
7 }
8
9 componentDidUpdate(prevProps) {
10 if (prevProps.id !== this.props.id) {
11 this.fetchData();
12 }
13 }
14
15 componentWillUnmount() {
16 this.cancelRequest();
17 }
18
19 fetchData = async () => {
20 const data = await fetch(`/api/${this.props.id}`);
21 this.setState({ data, loading: false });
22 };
23
24 cancelRequest = () => {
25 // Cleanup
26 };
27
28 render() {
29 if (this.state.loading) return <div>Loading...</div>;
30 return <div>{this.state.data}</div>;
31 }
32}
33
34// After: useEffect hook
35function DataFetcher({ id }) {
36 const [data, setData] = useState(null);
37 const [loading, setLoading] = useState(true);
38
39 useEffect(() => {
40 let cancelled = false;
41
42 const fetchData = async () => {
43 try {
44 const response = await fetch(`/api/${id}`);
45 const result = await response.json();
46
47 if (!cancelled) {
48 setData(result);
49 setLoading(false);
50 }
51 } catch (error) {
52 if (!cancelled) {
53 console.error(error);
54 }
55 }
56 };
57
58 fetchData();
59
60 // Cleanup function
61 return () => {
62 cancelled = true;
63 };
64 }, [id]); // Re-run when id changes
65
66 if (loading) return <div>Loading...</div>;
67 return <div>{data}</div>;
68}
Context and HOCs to Hooks
1// Before: Context consumer and HOC
2const ThemeContext = React.createContext();
3
4class ThemedButton extends React.Component {
5 static contextType = ThemeContext;
6
7 render() {
8 return (
9 <button style={{ background: this.context.theme }}>
10 {this.props.children}
11 </button>
12 );
13 }
14}
15
16// After: useContext hook
17function ThemedButton({ children }) {
18 const { theme } = useContext(ThemeContext);
19
20 return <button style={{ background: theme }}>{children}</button>;
21}
22
23// Before: HOC for data fetching
24function withUser(Component) {
25 return class extends React.Component {
26 state = { user: null };
27
28 componentDidMount() {
29 fetchUser().then((user) => this.setState({ user }));
30 }
31
32 render() {
33 return <Component {...this.props} user={this.state.user} />;
34 }
35 };
36}
37
38// After: Custom hook
39function useUser() {
40 const [user, setUser] = useState(null);
41
42 useEffect(() => {
43 fetchUser().then(setUser);
44 }, []);
45
46 return user;
47}
48
49function UserProfile() {
50 const user = useUser();
51 if (!user) return <div>Loading...</div>;
52 return <div>{user.name}</div>;
53}
React 18 Concurrent Features
New Root API
1// Before: React 17
2import ReactDOM from "react-dom";
3
4ReactDOM.render(<App />, document.getElementById("root"));
5
6// After: React 18
7import { createRoot } from "react-dom/client";
8
9const root = createRoot(document.getElementById("root"));
10root.render(<App />);
Automatic Batching
1// React 18: All updates are batched
2function handleClick() {
3 setCount((c) => c + 1);
4 setFlag((f) => !f);
5 // Only one re-render (batched)
6}
7
8// Even in async:
9setTimeout(() => {
10 setCount((c) => c + 1);
11 setFlag((f) => !f);
12 // Still batched in React 18!
13}, 1000);
14
15// Opt out if needed
16import { flushSync } from "react-dom";
17
18flushSync(() => {
19 setCount((c) => c + 1);
20});
21// Re-render happens here
22setFlag((f) => !f);
23// Another re-render
Transitions
1import { useState, useTransition } from "react";
2
3function SearchResults() {
4 const [query, setQuery] = useState("");
5 const [results, setResults] = useState([]);
6 const [isPending, startTransition] = useTransition();
7
8 const handleChange = (e) => {
9 // Urgent: Update input immediately
10 setQuery(e.target.value);
11
12 // Non-urgent: Update results (can be interrupted)
13 startTransition(() => {
14 setResults(searchResults(e.target.value));
15 });
16 };
17
18 return (
19 <>
20 <input value={query} onChange={handleChange} />
21 {isPending && <Spinner />}
22 <Results data={results} />
23 </>
24 );
25}
Suspense for Data Fetching
1import { Suspense } from "react";
2
3// Resource-based data fetching (with React 18)
4const resource = fetchProfileData();
5
6function ProfilePage() {
7 return (
8 <Suspense fallback={<Loading />}>
9 <ProfileDetails />
10 <Suspense fallback={<Loading />}>
11 <ProfileTimeline />
12 </Suspense>
13 </Suspense>
14 );
15}
16
17function ProfileDetails() {
18 // This will suspend if data not ready
19 const user = resource.user.read();
20 return <h1>{user.name}</h1>;
21}
22
23function ProfileTimeline() {
24 const posts = resource.posts.read();
25 return <Timeline posts={posts} />;
26}
Codemods for Automation
Run React Codemods
1# Install jscodeshift
2npm install -g jscodeshift
3
4# React 16.9 codemod (rename unsafe lifecycle methods)
5npx react-codeshift <transform> <path>
6
7# Example: Rename UNSAFE_ methods
8npx react-codeshift --parser=tsx \
9 --transform=react-codeshift/transforms/rename-unsafe-lifecycles.js \
10 src/
11
12# Update to new JSX Transform (React 17+)
13npx react-codeshift --parser=tsx \
14 --transform=react-codeshift/transforms/new-jsx-transform.js \
15 src/
16
17# Class to Hooks (third-party)
18npx codemod react/hooks/convert-class-to-function src/
Custom Codemod Example
1// custom-codemod.js
2module.exports = function (file, api) {
3 const j = api.jscodeshift;
4 const root = j(file.source);
5
6 // Find setState calls
7 root
8 .find(j.CallExpression, {
9 callee: {
10 type: "MemberExpression",
11 property: { name: "setState" },
12 },
13 })
14 .forEach((path) => {
15 // Transform to useState
16 // ... transformation logic
17 });
18
19 return root.toSource();
20};
21
22// Run: jscodeshift -t custom-codemod.js src/
Performance Optimization
useMemo and useCallback
1function ExpensiveComponent({ items, filter }) {
2 // Memoize expensive calculation
3 const filteredItems = useMemo(() => {
4 return items.filter((item) => item.category === filter);
5 }, [items, filter]);
6
7 // Memoize callback to prevent child re-renders
8 const handleClick = useCallback((id) => {
9 console.log("Clicked:", id);
10 }, []); // No dependencies, never changes
11
12 return <List items={filteredItems} onClick={handleClick} />;
13}
14
15// Child component with memo
16const List = React.memo(({ items, onClick }) => {
17 return items.map((item) => (
18 <Item key={item.id} item={item} onClick={onClick} />
19 ));
20});
Code Splitting
1import { lazy, Suspense } from "react";
2
3// Lazy load components
4const Dashboard = lazy(() => import("./Dashboard"));
5const Settings = lazy(() => import("./Settings"));
6
7function App() {
8 return (
9 <Suspense fallback={<Loading />}>
10 <Routes>
11 <Route path="/dashboard" element={<Dashboard />} />
12 <Route path="/settings" element={<Settings />} />
13 </Routes>
14 </Suspense>
15 );
16}
TypeScript Migration
1// Before: JavaScript
2function Button({ onClick, children }) {
3 return <button onClick={onClick}>{children}</button>;
4}
5
6// After: TypeScript
7interface ButtonProps {
8 onClick: () => void;
9 children: React.ReactNode;
10}
11
12function Button({ onClick, children }: ButtonProps) {
13 return <button onClick={onClick}>{children}</button>;
14}
15
16// Generic components
17interface ListProps<T> {
18 items: T[];
19 renderItem: (item: T) => React.ReactNode;
20}
21
22function List<T>({ items, renderItem }: ListProps<T>) {
23 return <>{items.map(renderItem)}</>;
24}
Migration Checklist
1### Pre-Migration
2
3- [ ] Update dependencies incrementally (not all at once)
4- [ ] Review breaking changes in release notes
5- [ ] Set up testing suite
6- [ ] Create feature branch
7
8### Class → Hooks Migration
9
10- [ ] Identify class components to migrate
11- [ ] Start with leaf components (no children)
12- [ ] Convert state to useState
13- [ ] Convert lifecycle to useEffect
14- [ ] Convert context to useContext
15- [ ] Extract custom hooks
16- [ ] Test thoroughly
17
18### React 18 Upgrade
19
20- [ ] Update to React 17 first (if needed)
21- [ ] Update react and react-dom to 18
22- [ ] Update @types/react if using TypeScript
23- [ ] Change to createRoot API
24- [ ] Test with StrictMode (double invocation)
25- [ ] Address concurrent rendering issues
26- [ ] Adopt Suspense/Transitions where beneficial
27
28### Performance
29
30- [ ] Identify performance bottlenecks
31- [ ] Add React.memo where appropriate
32- [ ] Use useMemo/useCallback for expensive operations
33- [ ] Implement code splitting
34- [ ] Optimize re-renders
35
36### Testing
37
38- [ ] Update test utilities (React Testing Library)
39- [ ] Test with React 18 features
40- [ ] Check for warnings in console
41- [ ] Performance testing
Resources
- references/breaking-changes.md: Version-specific breaking changes
- references/codemods.md: Codemod usage guide
- references/hooks-migration.md: Comprehensive hooks patterns
- references/concurrent-features.md: React 18 concurrent features
- assets/codemod-config.json: Codemod configurations
- assets/migration-checklist.md: Step-by-step checklist
- scripts/apply-codemods.sh: Automated codemod script
Best Practices
- Incremental Migration: Don’t migrate everything at once
- Test Thoroughly: Comprehensive testing at each step
- Use Codemods: Automate repetitive transformations
- Start Simple: Begin with leaf components
- Leverage StrictMode: Catch issues early
- Monitor Performance: Measure before and after
- Document Changes: Keep migration log
Common Pitfalls
- Forgetting useEffect dependencies
- Over-using useMemo/useCallback
- Not handling cleanup in useEffect
- Mixing class and functional patterns
- Ignoring StrictMode warnings
- Breaking change assumptions
What Users Are Saying
Real feedback from the community
Environment Matrix
Dependencies
Framework Support
Context Window
Security & Privacy
Information
- Author
- wshobson
- Updated
- 2026-01-30
- Category
- automation-tools
Related Skills
React Modernization
Upgrade React applications to latest versions, migrate from class components to hooks, and adopt …
View Details →Angular Modernization
Modernizes Angular code such as components and directives to follow best practices using both …
View Details →Angular Modernization
Modernizes Angular code such as components and directives to follow best practices using both …
View Details →