react-modernization

Guide for upgrading React applications, migrating patterns, and adopting modern features.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "react-modernization" with this command: npx skills add sivag-lab/roth_mcp/sivag-lab-roth-mcp-react-modernization

React Modernization

Guide for upgrading React applications, migrating patterns, and adopting modern features.

When to Use

  • Upgrading React to 18.x or 19.x

  • Migrating class components to function components with hooks

  • Adopting concurrent features (Suspense, Transitions, use())

  • Running codemods for automated transformations

  • Modernizing legacy patterns (HOCs to hooks, lifecycle to effects)

Upgrade Path

React 16/17 ──> React 18 ──> Adopt Concurrent Features ──> React 19 │ │ │ createRoot migration Suspense + Transitions use() + Actions Automatic batching useDeferredValue useOptimistic StrictMode changes Error Boundaries React Compiler

React 18 Migration

Breaking Changes

  • ReactDOM.render replaced by createRoot (required)

  • Automatic batching in all contexts (may change behavior)

  • Strict Mode double-renders effects in dev

Install & Codemod

npm install react@18 react-dom@18 @types/react@18 @types/react-dom@18 npx codemod react/19/replace-reactdom-render

// BEFORE (React 17) import ReactDOM from 'react-dom'; ReactDOM.render(<App />, document.getElementById('root'));

// AFTER (React 18+) import { createRoot } from 'react-dom/client'; createRoot(document.getElementById('root')!).render(<App />);

TypeScript Changes

  • React.FC no longer includes children — add explicitly to props

  • React.VFC removed — use React.FC

  • Stricter generics on useCallback / useMemo

Class to Function Component Migration

Priority Order

  • Leaf components (no children, simple props) — easiest wins

  • Container components (state + data fetching)

  • Higher-Order Components — extract to custom hooks

  • Ref-forwarding components — useRef + forwardRef

  • Error Boundaries — keep as class (no hook equivalent)

Lifecycle to Hooks Mapping

Class Lifecycle Hook Equivalent

constructor / state init useState(initialValue)

componentDidMount

useEffect(() => { ... }, [])

componentDidUpdate

useEffect(() => { ... }, [deps])

componentWillUnmount

useEffect return cleanup

shouldComponentUpdate

React.memo(Component)

getDerivedStateFromProps

Compute during render or useMemo

componentDidCatch

No hook — keep as class Error Boundary

Migration Example

// BEFORE: Class class UserProfile extends React.Component<Props, State> { state = { user: null, loading: true }; componentDidMount() { fetchUser(this.props.id).then(user => this.setState({ user, loading: false }) ); } componentDidUpdate(prev: Props) { if (prev.id !== this.props.id) { this.setState({ loading: true }); fetchUser(this.props.id).then(user => this.setState({ user, loading: false }) ); } } render() { if (this.state.loading) return <Spinner />; return <div>{this.state.user?.name}</div>; } }

// AFTER: Function + hooks function UserProfile({ id }: Props) { const [user, setUser] = useState<User | null>(null); const [loading, setLoading] = useState(true);

useEffect(() => { setLoading(true); fetchUser(id).then(u => { setUser(u); setLoading(false); }); }, [id]);

if (loading) return <Spinner />; return <div>{user?.name}</div>; }

HOC to Custom Hook

// BEFORE: HOC function withAuth(Component) { return (props) => { const user = useContext(AuthContext); if (!user) return <Redirect to="/login" />; return <Component {...props} user={user} />; }; }

// AFTER: Custom hook function useAuth() { const user = useContext(AuthContext); return { user, isAuthenticated: !!user }; }

Concurrent Features (React 18+)

Suspense Boundaries

<Suspense fallback={<Skeleton />}> <LazyComponent /> </Suspense>

useTransition — Non-Urgent Updates

const [isPending, startTransition] = useTransition();

function handleSearch(value: string) { setQuery(value); // Urgent: update input startTransition(() => setResults(filter(value))); // Deferred: filter }

useDeferredValue — Defer Expensive Renders

const deferredQuery = useDeferredValue(query); const results = useMemo(() => search(deferredQuery), [deferredQuery]);

React 19 Features

use() — Read Promises and Context

// Suspends until promise resolves function UserProfile({ userPromise }: { userPromise: Promise<User> }) { const user = use(userPromise); return <div>{user.name}</div>; }

// Conditional context reading (new in 19) function Theme({ show }: { show: boolean }) { if (!show) return null; const theme = use(ThemeContext); return <div style={{ color: theme.primary }}>Themed</div>; }

useActionState — Form Actions

const [state, formAction, isPending] = useActionState( async (prev, formData) => { const result = await login(formData); if (result.error) return { error: result.error }; redirect('/dashboard'); }, { error: null } );

return ( <form action={formAction}> <input name="email" type="email" /> <button disabled={isPending}> {isPending ? 'Signing in...' : 'Sign In'} </button> </form> );

useOptimistic — Optimistic UI

const [optimisticTodos, addOptimistic] = useOptimistic( todos, (state, newTodo: Todo) => [...state, newTodo] );

async function addTodo(formData: FormData) { const todo = { id: crypto.randomUUID(), text: formData.get('text') as string }; addOptimistic(todo); // Instant UI update await saveTodo(todo); // Server call }

Codemods

All React 19 codemods at once

npx codemod@latest react/19/migration-recipe

Individual codemods

npx codemod react/19/replace-reactdom-render # createRoot npx codemod react/19/replace-string-ref # string refs to useRef npx codemod react/19/replace-act-import # act() import path npx codemod react/19/replace-use-form-state # useFormState to useActionState

Migration Checklist

  • Update react, react-dom, and @types packages

  • Replace ReactDOM.render with createRoot

  • Run codemods for automated fixes

  • Fix TypeScript errors (FC children, etc.)

  • Test with StrictMode enabled (double-render effects)

  • Migrate class components (leaf first, then containers)

  • Replace HOCs with custom hooks

  • Add Suspense boundaries for code splitting

  • Adopt useTransition for non-urgent updates

  • Keep Error Boundaries as class components

  • Test all forms and user flows end-to-end

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

react-ui-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

commit

No summary provided by upstream source.

Repository SourceNeeds Review
General

ai-engineer

No summary provided by upstream source.

Repository SourceNeeds Review