Skills · Coding

React Modernization

Unverified29/40

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.

Originally by wshobson · MIT

Claude CodePartialHas SKILL.md but declares no allowed-tools — Claude Code will ask for permission each time
CursorPartialPlain prose you can paste in — but no Cursor rules file
CodexPartialPlain prose you can paste in — but no AGENTS.md
Gemini CLIPartialPlain prose you can paste in
CopilotPartialPlain prose you can paste in — but no Copilot instructions file
npx agentalley add react-modernization

This command does not work yet — the CLI is still being built. Until then, use Raw in the reader below to take the file.

Who is stuck, and on what

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.

The whole source

No sign-in, no blur, nothing truncated
react-modernization/SKILL.md329 lines6.7 KBRawView on GitHub
Frontmatter — 2 properties
namereact-modernization
descriptionUpgrade 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.
1---
2name: react-modernization
3description: 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.
4---A5No allowed-tools declared — no way to tell what this skill may touch
5 
6# React Modernization
7 
8Master React version upgrades, class to hooks migration, concurrent features adoption, and codemods for automated transformation.
9 
10## When to Use This Skill
11 
12- Upgrading React applications to latest versions
13- Migrating class components to functional components with hooks
14- Adopting concurrent React features (Suspense, transitions)
15- Applying codemods for automated refactoring
16- Modernizing state management patterns
17- Updating to TypeScript
18- Improving performance with React 18+ features
19 
20## Version Upgrade Path
21 
22### React 16 → 17 → 18
23 
24**Breaking Changes by Version:**
25 
26**React 17:**
27 
28- Event delegation changes
29- No event pooling
30- Effect cleanup timing
31- JSX transform (no React import needed)
32 
33**React 18:**
34 
35- Automatic batching
36- Concurrent rendering
37- Strict Mode changes (double invocation)
38- New root API
39- Suspense on server
40 
41## Class to Hooks Migration
42 
43### State Management
44 
45```javascript
46// Before: Class component
47class Counter extends React.Component {
48 constructor(props) {
49 super(props);
50 this.state = {
51 count: 0,
52 name: "",
53 };
54 }
55 
56 increment = () => {
57 this.setState({ count: this.state.count + 1 });
58 };
59 
60 render() {
61 return (
62 <div>
63 <p>Count: {this.state.count}</p>
64 <button onClick={this.increment}>Increment</button>
65 </div>
66 );
67 }
68}
69 
70// After: Functional component with hooks
71function Counter() {
72 const [count, setCount] = useState(0);
73 const [name, setName] = useState("");
74 
75 const increment = () => {
76 setCount(count + 1);
77 };
78 
79 return (
80 <div>
81 <p>Count: {count}</p>
82 <button onClick={increment}>Increment</button>
83 </div>
84 );
85}
86```
87 
88### Lifecycle Methods to Hooks
89 
90```javascript
91// Before: Lifecycle methods
92class DataFetcher extends React.Component {
93 state = { data: null, loading: true };
94 
95 componentDidMount() {
96 this.fetchData();
97 }
98 
99 componentDidUpdate(prevProps) {
100 if (prevProps.id !== this.props.id) {
101 this.fetchData();
102 }
103 }
104 
105 componentWillUnmount() {
106 this.cancelRequest();
107 }
108 
109 fetchData = async () => {
110 const data = await fetch(`/api/${this.props.id}`);A4This skill pulls in web or user content but never says to treat that content as data. A signal, not proof.
111 this.setState({ data, loading: false });
112 };
113 
114 cancelRequest = () => {
115 // Cleanup
116 };
117 
118 render() {
119 if (this.state.loading) return <div>Loading...</div>;
120 return <div>{this.state.data}</div>;
121 }
122}
123 
124// After: useEffect hook
125function DataFetcher({ id }) {
126 const [data, setData] = useState(null);
127 const [loading, setLoading] = useState(true);
128 
129 useEffect(() => {
130 let cancelled = false;
131 
132 const fetchData = async () => {
133 try {
134 const response = await fetch(`/api/${id}`);
135 const result = await response.json();
136 
137 if (!cancelled) {
138 setData(result);
139 setLoading(false);
140 }
141 } catch (error) {
142 if (!cancelled) {
143 console.error(error);
144 }
145 }
146 };
147 
148 fetchData();
149 
150 // Cleanup function
151 return () => {
152 cancelled = true;
153 };
154 }, [id]); // Re-run when id changes
155 
156 if (loading) return <div>Loading...</div>;
157 return <div>{data}</div>;
158}
159```
160 
161### Context and HOCs to Hooks
162 
163```javascript
164// Before: Context consumer and HOC
165const ThemeContext = React.createContext();
166 
167class ThemedButton extends React.Component {
168 static contextType = ThemeContext;
169 
170 render() {
171 return (
172 <button style={{ background: this.context.theme }}>
173 {this.props.children}
174 </button>
175 );
176 }
177}
178 
179// After: useContext hook
180function ThemedButton({ children }) {
181 const { theme } = useContext(ThemeContext);
182 
183 return <button style={{ background: theme }}>{children}</button>;
184}
185 
186// Before: HOC for data fetching
187function withUser(Component) {
188 return class extends React.Component {
189 state = { user: null };
190 
191 componentDidMount() {
192 fetchUser().then((user) => this.setState({ user }));
193 }
194 
195 render() {
196 return <Component {...this.props} user={this.state.user} />;
197 }
198 };
199}
200 
201// After: Custom hook
202function useUser() {
203 const [user, setUser] = useState(null);
204 
205 useEffect(() => {
206 fetchUser().then(setUser);
207 }, []);
208 
209 return user;
210}
211 
212function UserProfile() {
213 const user = useUser();
214 if (!user) return <div>Loading...</div>;
215 return <div>{user.name}</div>;
216}
217```
218 
219## React 18 Concurrent Features
220 
221### New Root API
222 
223```javascript
224// Before: React 17
225import ReactDOM from "react-dom";
226 
227ReactDOM.render(<App />, document.getElementById("root"));
228 
229// After: React 18
230import { createRoot } from "react-dom/client";
231 
232const root = createRoot(document.getElementById("root"));
233root.render(<App />);
234```
235 
236### Automatic Batching
237 
238```javascript
239// React 18: All updates are batched
240function handleClick() {
241 setCount((c) => c + 1);
242 setFlag((f) => !f);
243 // Only one re-render (batched)
244}
245 
246// Even in async:
247setTimeout(() => {
248 setCount((c) => c + 1);
249 setFlag((f) => !f);
250 // Still batched in React 18!
251}, 1000);
252 
253// Opt out if needed
254import { flushSync } from "react-dom";
255 
256flushSync(() => {
257 setCount((c) => c + 1);
258});
259// Re-render happens here
260setFlag((f) => !f);
261// Another re-render
262```
263 
264### Transitions
265 
266```javascript
267import { useState, useTransition } from "react";
268 
269function SearchResults() {
270 const [query, setQuery] = useState("");
271 const [results, setResults] = useState([]);
272 const [isPending, startTransition] = useTransition();
273 
274 const handleChange = (e) => {
275 // Urgent: Update input immediately
276 setQuery(e.target.value);
277 
278 // Non-urgent: Update results (can be interrupted)
279 startTransition(() => {
280 setResults(searchResults(e.target.value));
281 });
282 };
283 
284 return (
285 <>
286 <input value={query} onChange={handleChange} />
287 {isPending && <Spinner />}
288 <Results data={results} />
289 </>
290 );
291}
292```
293 
294### Suspense for Data Fetching
295 
296```javascript
297import { Suspense } from "react";
298 
299// Resource-based data fetching (with React 18)
300const resource = fetchProfileData();
301 
302function ProfilePage() {
303 return (
304 <Suspense fallback={<Loading />}>
305 <ProfileDetails />
306 <Suspense fallback={<Loading />}>
307 <ProfileTimeline />
308 </Suspense>
309 </Suspense>
310 );
311}
312 
313function ProfileDetails() {
314 // This will suspend if data not ready
315 const user = resource.user.read();
316 return <h1>{user.name}</h1>;
317}
318 
319function ProfileTimeline() {
320 const posts = resource.posts.read();
321 return <Timeline posts={posts} />;
322}
323```
324 
325## Additional patterns and templates
326 
327More detailed templates and worked examples live in `references/details.md`. Read that file for the full pattern library.
328 
329 

Reviews

Installed this one?Write the first review and take the Trailblazer badge.

Reviews only open after a real install, so this is empty — and we leave it empty rather than invent one.

Alternatives

Also in Coding