React Integration
Use Inval with React components, hooks, and the rendering lifecycle.
The Pattern
Inval is framework-agnostic. With React, you create Inval nodes outside components (or in refs) and subscribe to changes to trigger re-renders.
useInval.ts TYPESCRIPT
import { useRef, useEffect, useState } from 'react'
import { input, node, ComputedNode } from '@blu3ph4ntom/inval'
// Custom hook: creates an input node synced with React state
function useInvalInput<T>(initialValue: T) {
const nodeRef = useRef<InputNode<T>>(input(initialValue))
const [value, setValue] = useState(initialValue)
useEffect(() => {
nodeRef.current.set(value)
}, [value])
return [nodeRef.current, setValue] as const
}
// Custom hook: subscribes to a computed node
function useInvalNode<T>(computedNode: ComputedNode<T>) {
const [value, setValue] = useState(() => computedNode.get())
useEffect(() => {
// Re-read when React re-renders (parent changed deps)
setValue(computedNode.get())
})
return value
} Example: Responsive Chart
Chart.tsx TYPESCRIPT
import { useRef, useEffect, useState } from 'react'
import { input, node } from '@blu3ph4ntom/inval'
// Create graph outside component
const containerWidth = input(800)
const chartWidth = node({
dependsOn: { w: containerWidth },
compute: ({ w }) => w * 0.8
})
function Chart() {
const ref = useRef<HTMLDivElement>(null)
const [width, setWidth] = useState(800)
useEffect(() => {
const el = ref.current
if (!el) return
const observer = new ResizeObserver(entries => {
const w = entries[0].contentRect.width
containerWidth.set(w)
setWidth(w)
})
observer.observe(el)
return () => observer.disconnect()
}, [])
const computedWidth = chartWidth.get()
return (
<div ref={ref}>
<svg width={computedWidth} height={400}>
{/* chart content */}
</svg>
</div>
)
} Warning
Don't create Inval nodes inside the component body — they'll be recreated on every render. Use useRef or module-level declarations.