(null)
useEffect(() => {
async function load() {
try {
const response = await fetch("https://api.example.com/data")
const json = await response.json()
setData(json.items)
} catch (e) {
setError(e instanceof Error ? e.message : "Unknown error")
} finally {
setLoading(false)
}
}
load()
}, [])
if (loading) {
return Loading...
}
if (error) {
return Error: {error}
}
return (
{data?.map((item, i) => (
{item}
))}
)
}
```
## Animation Patterns
### Simple Animations
```tsx
import { useState, useEffect } from "react"
import { useTimeline } from "@opentui/react"
function ProgressBar() {
const [progress, setProgress] = useState(0)
const timeline = useTimeline({ duration: 3000 })
useEffect(() => {
timeline.add(
{ value: 0 },
{
value: 100,
duration: 3000,
ease: "linear",
onUpdate: (anim) => {
setProgress(Math.round(anim.targets[0].value))
},
}
)
}, [])
return (
Progress: {progress}%
)
}
```
### Interval-based Updates
```tsx
function Clock() {
const [time, setTime] = useState(new Date())
useEffect(() => {
const interval = setInterval(() => {
setTime(new Date())
}, 1000)
return () => clearInterval(interval)
}, [])
return {time.toLocaleTimeString()}
}
```
## Component Composition
### Render Props
```tsx
function Focusable({
children
}: {
children: (focused: boolean) => React.ReactNode
}) {
const [focused, setFocused] = useState(false)
return (
setFocused(true)}
onMouseUp={() => setFocused(false)}
>
{children(focused)}
)
}
// Usage
{(focused) => (
{focused ? "Focused!" : "Click me"}
)}
```
### Higher-Order Components
```tsx
function withBorder(
Component: React.ComponentType
,
borderStyle: string = "single"
) {
return function BorderedComponent(props: P) {
return (
)
}
}
// Usage
const BorderedText = withBorder(({ content }: { content: string }) => (
{content}
))
```