Skill flagged — suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

React Modernization

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

MIT-0 · Free to use, modify, and redistribute. No attribution required.
0 · 774 · 1 current installs · 3 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Suspicious
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
The skill claims to provide guidance for migrating React apps and the SKILL.md contains migration patterns, examples, and upgrade notes. It does mention 'automated codemods' but does not include any codemod scripts or request unrelated credentials — the scope of required resources is consistent with a documentation/instruction skill.
Instruction Scope
The instructions are focused on code migration patterns and migration checklists. They do not instruct the agent to read system files, access environment variables, or exfiltrate data. Note: the skill references automated codemods but provides no codemod artifacts in the package — if the agent or user later fetches or runs codemods from external sources, that introduces additional risk not covered by this skill alone.
Install Mechanism
There is no install spec and no code files — the skill is instruction-only. README shows example install commands (npx clawhub install, and an npx add line pointing to a GitHub tree) but these are documentation snippets rather than an install script embedded in the skill. No downloads or extracted archives are included.
Credentials
The skill declares no required environment variables, credentials, or config paths. Nothing in the SKILL.md accesses secrets or unrelated environment variables.
Persistence & Privilege
The skill is not set to always:true and does not request persistent or cross-skill configuration. Model invocation is not disabled (the platform default) — this is expected for skills and is not itself a red flag here.
Assessment
This skill is documentation-only and does not bundle code or request credentials, so its immediate footprint is small. Two practical cautions: (1) The guide mentions automated codemods but does not include them — if you or the agent fetches codemods from third-party URLs, review those scripts before running them (run on a branch/backup, inspect the code, and prefer official repo releases). (2) README contains example npx commands (one referencing a raw GitHub tree URL) that look nonstandard — treat any npx/add/download commands as potentially executing external code and verify the source before running. Otherwise, the skill appears coherent with its stated purpose.

Like a lobster shell, security has layers — review code before you run it.

Current versionv1.0.0
Download zip
latestvk971nd4t3tp6qyh3363xgpp00x80x6ep

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

SKILL.md

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 providerSimplified<Context> not <Context.Provider>
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 }) => <div>{data}</div>)

// 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 <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} />
}

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 <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
}

React 18+ Concurrent Features

New Root API (Required)

// 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 />)

useTransition for Non-Urgent Updates

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} />}
    </>
  )
}

Suspense for Data Fetching

// 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>
}

React 19: use() Hook

// 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>
}

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 (
    <form action={submitAction}>
      <input name="name" />
      <button disabled={isPending}>Update</button>
      {error && <p>{error}</p>}
    </form>
  )
}

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

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

Files

2 total
Select a file
Select a file to preview.

Comments

Loading comments…