Coding

React Modernization

Try it

Upgrade React apps by migrating class components to hooks, adopting React 18/19 concurrent features, running codemods, and adding TypeScript types.

What it does

Upgrade React applications from class components to hooks, adopt concurrent features, and migrate between major versions.

The skill document

React Modernization

Upgrade React applications from class components to hooks, adopt concurrent features, and migrate between major versions.

WHAT

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

WHEN

  • 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

KEYWORDS

react upgrade, class to hooks, useEffect, useState, react 18, react 19, concurrent, suspense, transition, codemod, migrate, modernize, functional component

Installation

OpenClaw / Moltbot / Clawbot

npx clawhub@latest install react-modernization

Version Upgrade Paths

React 17 → 18 Breaking Changes

ChangeImpactMigration
New root APIRequiredReactDOM.rendercreateRoot
Automatic batchingBehaviorState updates batch in async code now
Strict ModeDev onlyEffects fire twice (mount/unmount/mount)
Suspense on serverOptionalEnable SSR streaming

React 18 → 19 Breaking Changes

ChangeImpactMigration
use() hookNew APIRead promises/context in render
ref as propSimplifiedNo more forwardRef needed
Context as providerSimplifiednot
Async actionsNew patternuseActionState, useOptimistic

Class to Hooks Migration

Lifecycle Method Mappings

// 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 }) => {data})

// getDerivedStateFromProps → useMemo
const derivedValue = useMemo(() => computeFrom(props), [props])

State Migration Pattern

// 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 
    if (error) return 
    return 
  }
}

// AFTER: Custom hook + functional component
function useUser(id: string) {
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(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 
  if (error) return 
  return 
}

HOC to Hook Migration

// BEFORE: Higher-Order Component
function withUser(Component) {
  return function WithUser(props) {
    const [user, setUser] = useState(null)
    useEffect(() => { fetchUser().then(setUser) }, [])
    return 
  }
}

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 ? {user.name} : null
}

React 18+ Concurrent Features

New Root API (Required)

// BEFORE: React 17
import ReactDOM from 'react-dom'
ReactDOM.render(, document.getElementById('root'))

// AFTER: React 18+
import { createRoot } from 'react-dom/client'
const root = createRoot(document.getElementById('root')!)
root.render()

useTransition for Non-Urgent Updates

function SearchResults() {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])
  const [isPending, startTransition] = useTransition()

  function handleChange(e: React.ChangeEvent) {
    // Urgent: update input immediately
    setQuery(e.target.value)
    
    // Non-urgent: can be interrupted
    startTransition(() => {
      setResults(searchDatabase(e.target.value))
    })
  }

  return (
    <>
      
      {isPending ?  : }
    </>
  )
}

Suspense for Data Fetching

// With React 19's use() hook
function ProfilePage({ userId }: { userId: string }) {
  return (
    }>
      
    
  )
}

function ProfileDetails({ userId }: { userId: string }) {
  // use() suspends until promise resolves
  const user = use(fetchUser(userId))
  return {user.name}
}

React 19: use() Hook

// Read promises directly in render
function Comments({ commentsPromise }) {
  const comments = use(commentsPromise)
  return comments.map(c => )
}

// Read context (simpler than useContext)
function ThemeButton() {
  const theme = use(ThemeContext)
  return Click
}

React 19: Actions

// 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 (
    
      
      Update
      {error && {error}}
    
  )
}

Automated Codemods

Run Official React Codemods

# 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

Manual Search Patterns

# 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

TypeScript Migration

// Add types to functional components
interface ButtonProps {
  onClick: () => void
  children: React.ReactNode
  variant?: 'primary' | 'secondary'
}

function Button({ onClick, children, variant = 'primary' }: ButtonProps) {
  return (
    
      {children}
    
  )
}

// Type event handlers
function Form() {
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
  }
  
  const handleChange = (e: React.ChangeEvent) => {
    console.log(e.target.value)
  }

  return (
    
      
    
  )
}

// Generic components
interface ListProps {
  items: T[]
  renderItem: (item: T) => React.ReactNode
}

function List({ items, renderItem }: ListProps) {
  return <>{items.map(renderItem)}</>
}

Migration Checklist

Pre-Migration

  • Upgrade dependencies incrementally
  • Review breaking changes in release notes
  • Set up comprehensive test coverage
  • Create feature branch

Class → Hooks

  • 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

React 18+ Upgrade

  • Update to createRoot API
  • Test with StrictMode double-invocation
  • Address hydration mismatches
  • Adopt Suspense boundaries where beneficial
  • Use transitions for expensive updates

Post-Migration

  • Run full test suite
  • Check for console warnings
  • Profile performance before/after
  • Document changes for team

NEVER

  • 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

Related skills

Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.

by Iván854 installs69 stars

Adaptive web scraping in Python that bypasses anti-bot systems and scales from single requests to concurrent crawls.

by d4vinci399 installs28 stars

Query Twitter/X profiles, tweets, follower events, and KOL data through the 6551 REST API.

by infra403840 installs27 stars

Run Git operations — commits, branches, merges, rebases, conflict resolution, and recovery — with safety rules enforced.

by Iván532 installs31 stars

Post videos, photos, text, and documents to 10 social platforms through a single REST API call.

by victorcavero14375 installs50 stars

More from wpank

Browse all skills

Systematic code review patterns covering security, performance, maintainability, correctness, and testing — with severity levels, structured feedback guidance, review process, and anti-patterns to avoid. Use when reviewing PRs, establishing review standards, or improving review quality.

by wpank554 installs20 stars

Pragmatic coding standards for writing clean, maintainable code — naming, functions, structure, anti-patterns, and pre-edit safety checks. Use when writing new code, refactoring existing code, reviewing code quality, or establishing coding standards.

by wpank198 installs6 stars

Build reliable, fast E2E test suites with Playwright and Cypress. Critical user journey coverage, flaky test elimination, CI/CD integration.

by wpank336 installs6 stars

Build scalable, themable Tailwind CSS component libraries using CVA for variants, compound components, design tokens, dark mode, and responsive grids.

by wpank217 installs9 stars

Create software diagrams using Mermaid syntax. Use when users need to create, visualize, or document software through diagrams including class diagrams, sequence diagrams, flowcharts, ERDs, C4 architecture diagrams, state diagrams, git graphs, and other diagram types. Triggers include requests to diagram, visualize, model, map out, or show the flow of a system.

by wpank250 installs5 stars

Provides backend architecture patterns (Clean Architecture, Hexagonal, DDD) for building maintainable, testable, and scalable systems with clear layering and...

by wpank152 installs7 stars