---
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.