Title here
Summary here
// Menu component example
const Menu = ({ children }: { children: React.ReactNode }) => {
const [openItem, setOpenItem] = useState<string | null>(null)
return (
<MenuContext.Provider value={{ openItem, setOpenItem }}>
<nav>{children}</nav>
</MenuContext.Provider>
)
}
Menu.Item = ({ id, children }: { id: string; children: React.ReactNode }) => {
const { openItem, setOpenItem } = useMenuContext()
return (
<div onClick={() => setOpenItem(id)}>
{children}
</div>
)
}
interface ListProps<T> {
items: T[]
render: (item: T) => React.ReactNode
}
function List<T>({ items, render }: ListProps<T>) {
return (
<div>
{items.map((item, index) => (
<div key={index}>{render(item)}</div>
))}
</div>
)
}
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay)
return () => clearTimeout(timer)
}, [value, delay])
return debouncedValue
}
function useProjectData(projectId: string) {
const { data: project } = useProject(projectId)
const { data: metrics } = useMetrics(projectId)
const { data: activities } = useActivities(projectId)
return {
project,
metrics,
activities
}
}
// Container
const ProjectListContainer = () => {
const { data, isLoading } = useProjects()
return <ProjectList projects={data} isLoading={isLoading} />
}
// Presenter
const ProjectList = ({ projects, isLoading }: ProjectListProps) => {
if (isLoading) return <LoadingSpinner />
return (
<div>
{projects.map(project => (
<ProjectCard key={project.id} project={project} />
))}
</div>
)
}
type State = { count: number }
type Action = { type: 'increment' | 'decrement'; payload?: number }
function reducer(state: State, action: Action): State {
switch (action.action) {
case 'increment':
return { count: state.count + (action.payload ?? 1) }
case 'decrement':
return { count: state.count - (action.payload ?? 1) }
default:
return state
}
}
const FormBuilder = () => {
const { register, handleSubmit } = useForm()
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Input
{...register('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address'
}
})}
/>
</form>
)
}
const FormController = ({ control }: { control: Control<FormData> }) => {
return (
<Controller
name="select"
control={control}
rules={{ required: true }}
render={({ field }) => <Select {...field} />}
/>
)
}
class ErrorBoundary extends React.Component<Props, State> {
static getDerivedStateFromError(error: Error) {
return { hasError: true, error }
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
logErrorToService(error, errorInfo)
}
render() {
if (this.state.hasError) {
return <ErrorFallback error={this.state.error} />
}
return this.props.children
}
}
const AsyncComponent = () => {
const [error, setError] = useState<Error | null>(null)
const handleAsyncOperation = async () => {
try {
await someAsyncOperation()
} catch (err) {
setError(err as Error)
}
}
if (error) return <ErrorMessage error={error} />
return <div>Content</div>
}
const MemoizedComponent = React.memo(({ data }: Props) => {
return <ExpensiveRendering data={data} />
}, (prevProps, nextProps) => {
return prevProps.data.id === nextProps.data.id
})
const VirtualList = ({ items }: { items: Item[] }) => {
const [visibleItems, setVisibleItems] = useState<Item[]>([])
useEffect(() => {
const observer = new IntersectionObserver(
entries => {
// Update visible items based on intersection
},
{ threshold: 0.5 }
)
return () => observer.disconnect()
}, [])
return (
<div className="virtual-list">
{visibleItems.map(item => (
<ListItem key={item.id} item={item} />
))}
</div>
)
}