# Cline Rules: Runtime React 19 Upgrade
## Task Context
Upgrading noodl-viewer-react runtime from React 16.8 to React 19. This is the code that runs in deployed user projects.
## Key Constraints
### DO NOT
- Touch the editor code (noodl-editor) - that's a separate task
- Remove any existing node functionality
- Change the public API of `window.Noodl._viewerReact`
- Batch multiple large changes in one commit
### MUST DO
- Backup files before replacing
- Test after each significant change
- Watch browser console for React errors
- Preserve existing node behavior exactly
## Critical Files
### Replace These React Bundles
```
packages/noodl-viewer-react/static/shared/react.production.min.js
packages/noodl-viewer-react/static/shared/react-dom.production.min.js
```
Source: https://unpkg.com/react@19/umd/
### Update Entry Point (location TBD - search for it)
Find where `_viewerReact.render` is defined and change:
```javascript
// OLD
ReactDOM.render(, element);
// NEW
import { createRoot } from 'react-dom/client';
const root = createRoot(element);
root.render();
```
### Update SSR
```
packages/noodl-viewer-react/static/ssr/package.json // Change React version
packages/noodl-viewer-react/static/ssr/index.js // May need API updates
```
## Search Patterns for Broken Code
Run these and fix any matches:
```bash
# CRITICAL - These are REMOVED in React 19
grep -rn "componentWillMount" src/
grep -rn "componentWillReceiveProps" src/
grep -rn "componentWillUpdate" src/
grep -rn "UNSAFE_componentWill" src/
# REMOVED - String refs
grep -rn 'ref="' src/
grep -rn "ref='" src/
# REMOVED - Legacy context
grep -rn "contextTypes" src/
grep -rn "childContextTypes" src/
grep -rn "getChildContext" src/
```
## Lifecycle Migration Patterns
### componentWillMount → componentDidMount
```javascript
// Just move the code - componentDidMount runs after first render but that's usually fine
componentDidMount() {
// code that was in componentWillMount
}
```
### componentWillReceiveProps → getDerivedStateFromProps
```javascript
static getDerivedStateFromProps(props, state) {
if (props.value !== state.prevValue) {
return { computed: derive(props.value), prevValue: props.value };
}
return null;
}
```
### String refs → createRef
```javascript
// OLD
this.refs.myInput.focus();
// NEW
this.myInputRef = React.createRef();
this.myInputRef.current.focus();
```
## Testing Checkpoints
After each phase, verify in browser:
1. ✓ Editor preview loads without console errors
2. ✓ Basic nodes render (Group, Text, Button)
3. ✓ Click events fire signals
4. ✓ Hover states work
5. ✓ Repeater renders lists
6. ✓ Deploy build works
## Red Flags - Stop and Ask
- White screen with no console output
- "Invalid hook call" error
- Any error mentioning "fiber" or "reconciler"
- Build fails after React bundle replacement
## Commit Strategy
```
feat(runtime): replace React bundles with v19
feat(runtime): migrate entry point to createRoot
fix(runtime): update [node-name] for React 19 compatibility
feat(runtime): update SSR for React 19
docs: add React 19 migration guide
```
## When Done
- [ ] All grep searches return zero results for deprecated patterns
- [ ] Editor preview works
- [ ] Deploy build works
- [ ] No React warnings in console
- [ ] SSR still functions (if it was working before)