# Task: React 19 Node Modernization
## Overview
Update all frontend visual nodes in `noodl-viewer-react` to take advantage of React 19 features, remove deprecated patterns, and prepare the infrastructure for future React 19-only features like View Transitions.
**Priority:** High
**Estimated Effort:** 16-24 hours
**Branch:** `feature/react19-node-modernization`
---
## Background
With the editor upgraded to React 19 and the runtime to React 18.3 (95% compatible), we have an opportunity to modernize our node infrastructure. This work removes technical debt, simplifies code, and prepares the foundation for React 19-exclusive features.
### React 19 Changes That Affect Nodes
1. **`ref` as a regular prop** - No more `forwardRef` wrapper needed
2. **Improved `useTransition`** - Can now handle async functions
3. **`useDeferredValue` with initial value** - New parameter for better loading states
4. **Native document metadata** - `
`, `` render directly
5. **Better Suspense** - Works with more scenarios
6. **`use()` hook** - Read resources in render (promises, context)
7. **Form actions** - `useActionState`, `useFormStatus`, `useOptimistic`
8. **Cleaner cleanup** - Ref cleanup functions
---
## Phase 1: Infrastructure Updates
### 1.1 Update `createNodeFromReactComponent` Wrapper
**File:** `packages/noodl-viewer-react/src/react-component-node.js` (or `.ts`)
**Changes:**
- Remove automatic `forwardRef` wrapping logic
- Add support for `ref` as a standard prop
- Add optional `useTransition` integration for state updates
- Add optional `useDeferredValue` wrapper for specified inputs
**New Options:**
```javascript
createNodeFromReactComponent({
// ... existing options
// NEW: React 19 options
react19: {
// Enable transition wrapping for specified inputs
transitionInputs: ['items', 'filter'],
// Enable deferred value for specified inputs
deferredInputs: ['searchQuery'],
// Enable form action support
formActions: true,
}
})
```
### 1.2 Update Base Node Classes
**Files:**
- `packages/noodl-viewer-react/src/nodes/std-library/visual-base.js`
- Any shared base classes for visual nodes
**Changes:**
- Remove `forwardRef` patterns
- Update ref handling to use callback ref pattern
- Add utility methods for transitions:
- `this.startTransition(callback)` - wrap updates in transition
- `this.getDeferredValue(inputName)` - get deferred version of input
### 1.3 Update TypeScript Definitions
**Files:**
- `packages/noodl-viewer-react/static/viewer/global.d.ts.keep`
- Any relevant `.d.ts` files
**Changes:**
- Update component prop types to include `ref` as regular prop
- Add types for new React 19 hooks
- Update `Noodl` namespace types if needed
---
## Phase 2: Core Visual Nodes
### 2.1 Group Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/group.js`
**Current Issues:**
- Likely uses `forwardRef` or class component with ref forwarding
- May have legacy lifecycle patterns
**Updates:**
- Convert to functional component with `ref` as prop
- Use `useEffect` cleanup returns properly
- Add optional `useDeferredValue` for children rendering (large lists)
**New Capabilities:**
- `Defer Children` input (boolean) - uses `useDeferredValue` for smoother updates
- `Is Updating` output - true when deferred update pending
### 2.2 Text Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/text.js`
**Updates:**
- Remove `forwardRef` wrapper
- Simplify ref handling
### 2.3 Image Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/image.js`
**Updates:**
- Remove `forwardRef` wrapper
- Add resource preloading hints for React 19's `preload()` API (future enhancement slot)
### 2.4 Video Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/video.js`
**Updates:**
- Remove `forwardRef` wrapper
- Ensure ref cleanup is proper
### 2.5 Circle Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/circle.js`
**Updates:**
- Remove `forwardRef` wrapper
### 2.6 Icon Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/icon.js` (or `net.noodl.visual.icon`)
**Updates:**
- Remove `forwardRef` wrapper
---
## Phase 3: UI Control Nodes
### 3.1 Button Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/button.js` (or `net.noodl.controls.button`)
**Updates:**
- Remove `forwardRef` wrapper
- Add form action support preparation:
- `formAction` input (string) - for future form integration
- `Is Pending` output - when used in form with pending action
### 3.2 Text Input Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/textinput.js`
**Updates:**
- Remove `forwardRef` wrapper
- Consider `useDeferredValue` for `onChange` value updates
- Add form integration preparation
**New Capabilities (Optional):**
- `Defer Updates` input - delays `Value` output updates for performance
- `Immediate Value` output - non-deferred value for UI feedback
### 3.3 Checkbox Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/checkbox.js`
**Updates:**
- Remove `forwardRef` wrapper
- Add optimistic update preparation (`useOptimistic` slot)
### 3.4 Radio Button / Radio Button Group
**Files:**
- `packages/noodl-viewer-react/src/nodes/std-library/radiobutton.js`
- `packages/noodl-viewer-react/src/nodes/std-library/radiobuttongroup.js`
**Updates:**
- Remove `forwardRef` wrappers
- Ensure proper group state management
### 3.5 Options/Dropdown Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/options.js`
**Updates:**
- Remove `forwardRef` wrapper
- Consider `useDeferredValue` for large option lists
### 3.6 Range/Slider Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/range.js`
**Updates:**
- Remove `forwardRef` wrapper
- `useDeferredValue` for value output (prevent render thrashing during drag)
**New Capabilities:**
- `Deferred Value` output - smoothed value for expensive downstream renders
- `Immediate Value` output - raw value for UI display
---
## Phase 4: Navigation Nodes
### 4.1 Page Router / Router Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/router.js`
**Updates:**
- Add `useTransition` wrapping for navigation
- Prepare for View Transitions API integration
**New Capabilities:**
- `Is Transitioning` output - true during page transition
- `Use Transition` input (boolean, default true) - wrap navigation in React transition
### 4.2 Router Navigate Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/routernavigate.js`
**Updates:**
- Wrap navigation in `startTransition`
**New Capabilities:**
- `Is Pending` output - navigation in progress
- `Transition Priority` input (enum: 'normal', 'urgent') - for future prioritization
### 4.3 Page Stack / Component Stack
**File:** `packages/noodl-viewer-react/src/nodes/std-library/pagestack.js`
**Updates:**
- Add `useTransition` for push/pop operations
**New Capabilities:**
- `Is Transitioning` output
- Prepare for animation coordination with View Transitions
### 4.4 Page Inputs Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/pageinputs.js`
**Updates:**
- Standard cleanup, ensure no deprecated patterns
### 4.5 Popup Nodes
**Files:**
- `packages/noodl-viewer-react/src/nodes/std-library/showpopup.js`
- `packages/noodl-viewer-react/src/nodes/std-library/closepopup.js`
**Updates:**
- Consider `useTransition` for popup show/hide
---
## Phase 5: Layout Nodes
### 5.1 Columns Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/columns.js`
**Updates:**
- Remove `forwardRef` wrapper
- Remove `React.cloneElement` if present (React 19 has better patterns)
- Consider using CSS Grid native features
### 5.2 Repeater (For Each) Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/foreach.js`
**Critical Updates:**
- Add `useDeferredValue` for items array
- Add `useTransition` for item updates
**New Capabilities:**
- `Defer Updates` input (boolean) - uses deferred value for items
- `Is Updating` output - true when deferred update pending
- `Transition Updates` input (boolean) - wrap updates in transition
**Why This Matters:**
Large list updates currently cause jank. With these options:
- User toggles `Defer Updates` → list updates don't block UI
- `Is Updating` output → can show loading indicator
### 5.3 Component Children Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/componentchildren.js`
**Updates:**
- Standard cleanup
---
## Phase 6: Data/Object Nodes
### 6.1 Component Object Node
**File:** `packages/noodl-viewer-react/src/nodes/std-library/componentobject.js`
**Updates:**
- Consider context-based implementation for React 19
- `use(Context)` can now be called conditionally in React 19
### 6.2 Parent Component Object Node
**File:** Similar location
**Updates:**
- Same as Component Object
---
## Phase 7: SEO/Document Nodes (New Capability)
### 7.1 Update Page Node for Document Metadata
**File:** `packages/noodl-viewer-react/src/nodes/std-library/page.js`
**New Capabilities:**
React 19 allows rendering ``, ``, `` directly in components and they hoist to ``.
**New Inputs:**
- `Page Title` - renders `` (already exists, but implementation changes)
- `Meta Description` - renders ``
- `Meta Keywords` - renders ``
- `Canonical URL` - renders ``
- `OG Title` - renders ``
- `OG Description` - renders ``
- `OG Image` - renders ``
**Implementation:**
```jsx
function PageComponent({ title, description, ogTitle, ...props }) {
return (
<>
{title && {title}}
{description && }
{ogTitle && }
{/* ... rest of component */}
>
);
}
```
This replaces the hacky SSR string replacement currently in `packages/noodl-viewer-react/static/ssr/index.js`.
---
## Phase 8: Testing & Validation
### 8.1 Unit Tests
**Update/Create Tests For:**
- `createNodeFromReactComponent` with new options
- Each updated node renders correctly
- Ref forwarding works without `forwardRef`
- Deferred values update correctly
- Transitions wrap updates properly
### 8.2 Integration Tests
- Page navigation with transitions
- Repeater with large datasets
- Form interactions with new patterns
### 8.3 Visual Regression Tests
- Ensure no visual changes from modernization
- Test all visual states (hover, pressed, disabled)
- Test variants still work
### 8.4 Performance Benchmarks
**Before/After Metrics:**
- Repeater with 1000 items - render time
- Page navigation - transition smoothness
- Text input rapid typing - lag measurement
---
## File List Summary
### Infrastructure Files
```
packages/noodl-viewer-react/src/
├── react-component-node.js # Main wrapper factory
├── nodes/std-library/
│ └── visual-base.js # Base class for visual nodes
```
### Visual Element Nodes
```
packages/noodl-viewer-react/src/nodes/std-library/
├── group.js
├── text.js
├── image.js
├── video.js
├── circle.js
├── icon.js (or net.noodl.visual.icon)
```
### UI Control Nodes
```
packages/noodl-viewer-react/src/nodes/std-library/
├── button.js (or net.noodl.controls.button)
├── textinput.js
├── checkbox.js
├── radiobutton.js
├── radiobuttongroup.js
├── options.js
├── range.js
```
### Navigation Nodes
```
packages/noodl-viewer-react/src/nodes/std-library/
├── router.js
├── routernavigate.js
├── pagestack.js
├── pageinputs.js
├── showpopup.js
├── closepopup.js
```
### Layout Nodes
```
packages/noodl-viewer-react/src/nodes/std-library/
├── columns.js
├── foreach.js
├── componentchildren.js
```
### Data Nodes
```
packages/noodl-viewer-react/src/nodes/std-library/
├── componentobject.js
├── parentcomponentobject.js
```
### Page/SEO Nodes
```
packages/noodl-viewer-react/src/nodes/std-library/
├── page.js
```
### Type Definitions
```
packages/noodl-viewer-react/static/viewer/
├── global.d.ts.keep
```
---
## Implementation Order
### Week 1: Foundation
1. Update `createNodeFromReactComponent` infrastructure
2. Update base classes
3. Update Group node (most used, good test case)
4. Update Text node
5. Create test suite for modernized patterns
### Week 2: Controls & Navigation
6. Update all UI Control nodes (Button, TextInput, etc.)
7. Update Navigation nodes with transition support
8. Update Repeater with deferred value support
9. Test navigation flow end-to-end
### Week 3: Polish & New Features
10. Update remaining nodes (Columns, Component Object, etc.)
11. Add Page metadata support
12. Performance testing and optimization
13. Documentation updates
---
## Success Criteria
### Must Have
- [ ] All nodes render correctly after updates
- [ ] No `forwardRef` usage in visual nodes
- [ ] All refs work correctly (DOM access, focus, etc.)
- [ ] No breaking changes to existing projects
- [ ] Tests pass
### Should Have
- [ ] Repeater has `Defer Updates` option
- [ ] Page Router has `Is Transitioning` output
- [ ] Page node has SEO metadata inputs
### Nice to Have
- [ ] Performance improvement measurable in benchmarks
- [ ] Text Input deferred value option
- [ ] Range slider deferred value option
---
## Migration Notes
### Backward Compatibility
These changes should be **fully backward compatible**:
- Existing projects continue to work unchanged
- New features are opt-in via new inputs
- No changes to how nodes are wired together
### Runtime Considerations
Since runtime is React 18.3:
- `useTransition` works (available since React 18)
- `useDeferredValue` works (available since React 18)
- `ref` as prop works (React 18.3 forward-ported this)
- Native metadata hoisting does NOT work (React 19 only)
- For runtime, metadata nodes will need polyfill/fallback
**Strategy:** Build features for React 19 editor, provide graceful degradation for React 18.3 runtime. Eventually upgrade runtime to React 19.
---
## Code Examples
### Before: forwardRef Pattern
```javascript
getReactComponent() {
return React.forwardRef((props, ref) => {
return
{props.children}
;
});
}
```
### After: ref as Prop Pattern
```javascript
getReactComponent() {
return function GroupComponent({ ref, style, children }) {
return