--- title: Reactivity in React description: Learn how to handle state changes for head tags in React - from basic state updates to complex data flows. navigation: title: 'Reactivity' --- ## Introduction Unhead integrates with React's state management system through the React Context API. This guide explains how to effectively manage reactive head tags in your React applications. ## How Unhead Works in React Unhead uses React's Context API to provide head management throughout your component tree. The integration automatically tracks changes to your React state and updates the document head accordingly. ## Using the UnheadProvider Unlike [React Helmet](https://github.com/afl/react-helmet), Unhead uses the provider pattern for isolation - keeping head state contained and manageable rather than global: ```tsx import { createHead, UnheadProvider } from '@unhead/react' // Create head instance with custom options const head = createHead() function App() { return ( ) } ``` This pattern prevents many hydration and testing headaches by keeping head state contained. ## Basic Reactivity React's state management system works naturally with Unhead. When you pass state to `useHead()`, the head tags update whenever the state changes: ```tsx import { useHead } from '@unhead/react' import { useState } from 'react' function PageHead() { const [title, setTitle] = useState('Welcome to My App') // Head tags will update when title state changes useHead({ title }) return ( ) } ``` ## Async Head Updates It's common to update head tags based on asynchronous data: ```tsx import { useHead } from '@unhead/react' import { useEffect, useState } from 'react' function PageHead() { const [title, setTitle] = useState('Loading...') useEffect(() => { async function loadData() { const response = await fetch('/api/page') const data = await response.json() setTitle(data.title) } loadData() }, []) useHead({ title }) return null } ``` ## Managing Complex Head Data For pages with multiple meta tags, you can manage them together in a structured way: ```tsx function ProductHead({ id }) { const [product, setProduct] = useState({ title: 'Loading...', description: '', image: '/placeholder.jpg', price: '' }) useEffect(() => { fetchProduct(id).then(setProduct) }, [id]) useHead({ title: product.title, meta: [ { name: 'description', content: product.description }, { property: 'og:image', content: product.image }, { property: 'product:price', content: product.price } ] }) return null } ``` ## Using with Data Libraries Unhead works well with popular data fetching libraries: ### React Query Example ```tsx import { useQuery } from '@tanstack/react-query' import { useHead } from '@unhead/react' function PageHead({ id }) { const { data = { title: 'Loading...', description: '' } } = useQuery({ queryKey: ['page', id], queryFn: () => fetchPage(id) }) useHead({ title: data.title, meta: [ { name: 'description', content: data.description } ] }) return null } ``` ### SWR Example ```tsx import { useHead } from '@unhead/react' import useSWR from 'swr' function PageHead({ slug }) { const { data = { title: 'Loading...', description: '' } } = useSWR( `/api/pages/${slug}`, fetcher ) useHead({ title: data.title, meta: [ { name: 'description', content: data.description } ] }) return null } ``` ## Performance Optimization For optimal performance with Unhead in React: ### Memoize Complex Head Configurations Use `useMemo` for complex head configurations to prevent unnecessary re-renders: ```tsx import { useHead } from '@unhead/react' import { useMemo } from 'react' function SEOHead({ title, description, image }) { const headConfig = useMemo(() => ({ title, meta: [ { name: 'description', content: description }, { property: 'og:title', content: title }, { property: 'og:description', content: description }, { property: 'og:image', content: image } ] }), [title, description, image]) useHead(headConfig) return null } ``` ### Code Splitting for Head Components Leverage code-splitting for head components to reduce initial bundle size: ```tsx import { lazy } from 'react' // Load head components only when needed const ProductHead = lazy(() => import('./ProductHead')) const BlogHead = lazy(() => import('./BlogHead')) function App() { return ( )} /> )} /> ) } ``` ## Implementation Details Under the hood, Unhead in React: 1. Uses React's Context API for head instance management 2. Integrates with React's lifecycle using `useEffect` and state hooks 3. Creates head entries that update when input props change 4. Automatically cleans up when components unmount The implementation wraps head entries with React state management that: - Patches the entry when input data changes - Disposes of the entry when the component is unmounted ## Best Practices 1. **Keep Head Components Focused**: Create dedicated components for head management that are separate from UI components. 2. **Handle Loading States**: Always provide fallback values for async data to prevent undefined errors. 3. **Use Component Composition**: Compose multiple head components for complex pages: ```tsx function ProductPage({ id }) { return ( <> {' '} {/* Global site metadata */} {' '} {/* Product-specific metadata */} {' '} {/* Structured data */} {/* UI components */} ) } ``` 4. **Cleanup Happens Automatically**: Unhead handles cleanup when components unmount through React's effect cleanup system.