Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Upgrade React apps by migrating class components to hooks, adopting React 18/19 concurrent features, running codemods, and adding TypeScript types.
Upgrade React apps by migrating class components to hooks, adopting React 18/19 concurrent features, running codemods, and adding TypeScript types.
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run.
Upgrade React applications from class components to hooks, adopt concurrent features, and migrate between major versions.
Systematic patterns for modernizing React codebases: Class-to-hooks migration with lifecycle method mappings React 18/19 concurrent features adoption TypeScript migration for React components Automated codemods for bulk refactoring Performance optimization with modern APIs
Migrating class components to functional components with hooks Upgrading React 16/17 apps to React 18/19 Adopting concurrent features (Suspense, transitions, use) Converting HOCs and render props to custom hooks Adding TypeScript to React projects
react upgrade, class to hooks, useEffect, useState, react 18, react 19, concurrent, suspense, transition, codemod, migrate, modernize, functional component
npx clawhub@latest install react-modernization
ChangeImpactMigrationNew root APIRequiredReactDOM.render โ createRootAutomatic batchingBehaviorState updates batch in async code nowStrict ModeDev onlyEffects fire twice (mount/unmount/mount)Suspense on serverOptionalEnable SSR streaming
ChangeImpactMigrationuse() hookNew APIRead promises/context in renderref as propSimplifiedNo more forwardRef neededContext as providerSimplified<Context> not <Context.Provider>Async actionsNew patternuseActionState, useOptimistic
// componentDidMount โ useEffect with empty deps useEffect(() => { fetchData() }, []) // componentDidUpdate โ useEffect with deps useEffect(() => { updateWhenIdChanges() }, [id]) // componentWillUnmount โ useEffect cleanup useEffect(() => { const subscription = subscribe() return () => subscription.unsubscribe() }, []) // shouldComponentUpdate โ React.memo const Component = React.memo(({ data }) => <div>{data}</div>) // getDerivedStateFromProps โ useMemo const derivedValue = useMemo(() => computeFrom(props), [props])
// BEFORE: Class with multiple state properties class UserProfile extends React.Component { state = { user: null, loading: true, error: null } componentDidMount() { fetchUser(this.props.id) .then(user => this.setState({ user, loading: false })) .catch(error => this.setState({ error, loading: false })) } componentDidUpdate(prevProps) { if (prevProps.id !== this.props.id) { this.setState({ loading: true }) fetchUser(this.props.id) .then(user => this.setState({ user, loading: false })) } } render() { const { user, loading, error } = this.state if (loading) return <Spinner /> if (error) return <Error message={error.message} /> return <Profile user={user} /> } } // AFTER: Custom hook + functional component function useUser(id: string) { const [user, setUser] = useState<User | null>(null) const [loading, setLoading] = useState(true) const [error, setError] = useState<Error | null>(null) useEffect(() => { let cancelled = false setLoading(true) fetchUser(id) .then(data => { if (!cancelled) { setUser(data) setLoading(false) } }) .catch(err => { if (!cancelled) { setError(err) setLoading(false) } }) return () => { cancelled = true } }, [id]) return { user, loading, error } } function UserProfile({ id }: { id: string }) { const { user, loading, error } = useUser(id) if (loading) return <Spinner /> if (error) return <Error message={error.message} /> return <Profile user={user} /> }
// BEFORE: Higher-Order Component function withUser(Component) { return function WithUser(props) { const [user, setUser] = useState(null) useEffect(() => { fetchUser().then(setUser) }, []) return <Component {...props} user={user} /> } } const ProfileWithUser = withUser(Profile) // AFTER: Custom hook (simpler, composable) function useCurrentUser() { const [user, setUser] = useState(null) useEffect(() => { fetchUser().then(setUser) }, []) return user } function Profile() { const user = useCurrentUser() return user ? <div>{user.name}</div> : null }
// BEFORE: React 17 import ReactDOM from 'react-dom' ReactDOM.render(<App />, document.getElementById('root')) // AFTER: React 18+ import { createRoot } from 'react-dom/client' const root = createRoot(document.getElementById('root')!) root.render(<App />)
function SearchResults() { const [query, setQuery] = useState('') const [results, setResults] = useState([]) const [isPending, startTransition] = useTransition() function handleChange(e: React.ChangeEvent<HTMLInputElement>) { // Urgent: update input immediately setQuery(e.target.value) // Non-urgent: can be interrupted startTransition(() => { setResults(searchDatabase(e.target.value)) }) } return ( <> <input value={query} onChange={handleChange} /> {isPending ? <Spinner /> : <ResultsList data={results} />} </> ) }
// With React 19's use() hook function ProfilePage({ userId }: { userId: string }) { return ( <Suspense fallback={<ProfileSkeleton />}> <ProfileDetails userId={userId} /> </Suspense> ) } function ProfileDetails({ userId }: { userId: string }) { // use() suspends until promise resolves const user = use(fetchUser(userId)) return <h1>{user.name}</h1> }
// Read promises directly in render function Comments({ commentsPromise }) { const comments = use(commentsPromise) return comments.map(c => <Comment key={c.id} {...c} />) } // Read context (simpler than useContext) function ThemeButton() { const theme = use(ThemeContext) return <button className={theme}>Click</button> }
// useActionState for form submissions function UpdateName() { const [error, submitAction, isPending] = useActionState( async (previousState, formData) => { const error = await updateName(formData.get('name')) if (error) return error redirect('/profile') }, null ) return ( <form action={submitAction}> <input name="name" /> <button disabled={isPending}>Update</button> {error && <p>{error}</p>} </form> ) }
# Update to new JSX transform (no React import needed) npx codemod@latest react/19/replace-reactdom-render # Update deprecated APIs npx codemod@latest react/19/replace-string-ref # Class to function components npx codemod@latest react/19/replace-use-form-state
# Find class components rg "class \w+ extends (React\.)?Component" --type tsx # Find deprecated lifecycle methods rg "componentWillMount|componentWillReceiveProps|componentWillUpdate" --type tsx # Find ReactDOM.render (needs migration to createRoot) rg "ReactDOM\.render" --type tsx
// Add types to functional components interface ButtonProps { onClick: () => void children: React.ReactNode variant?: 'primary' | 'secondary' } function Button({ onClick, children, variant = 'primary' }: ButtonProps) { return ( <button onClick={onClick} className={variant}> {children} </button> ) } // Type event handlers function Form() { const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault() } const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { console.log(e.target.value) } return ( <form onSubmit={handleSubmit}> <input onChange={handleChange} /> </form> ) } // Generic components interface ListProps<T> { items: T[] renderItem: (item: T) => React.ReactNode } function List<T>({ items, renderItem }: ListProps<T>) { return <>{items.map(renderItem)}</> }
Upgrade dependencies incrementally Review breaking changes in release notes Set up comprehensive test coverage Create feature branch
Start with leaf components (no children) Convert state to useState Convert lifecycle to useEffect Extract shared logic to custom hooks Convert HOCs to hooks where possible
Update to createRoot API Test with StrictMode double-invocation Address hydration mismatches Adopt Suspense boundaries where beneficial Use transitions for expensive updates
Run full test suite Check for console warnings Profile performance before/after Document changes for team
Skip testing after migration Migrate multiple components in one commit Ignore StrictMode warnings (they reveal bugs) Use // eslint-disable-next-line react-hooks/exhaustive-deps without understanding why Mix class and hooks in same component
Code helpers, APIs, CLIs, browser automation, testing, and developer operations.
Largest current source with strong distribution and engagement signals.