Sharing React Context with AI
The useAIContext
hook allows React components to share their state with the AI without causing re-renders. This enables the AI to provide personalized responses based on user data, app settings, and component state.
User Profile
App Settings
Current AI Context (0 items)
AI with Shared Context
• AI knows your profile, settings, and session stateHow Context Sharing Works
Context sharing creates a bridge between your React state and the AI model:
- No Re-renders: Context updates don’t trigger chat interface re-renders
- Automatic Updates: When state changes, context is automatically updated
- Structured Data: Context items include metadata for better AI understanding
- Priority System: Control which context is most important to the AI
- Lifecycle Management: Context is automatically cleaned up when components unmount
Basic Usage
The useAIContext
hook accepts an options object:
import { useAIContext } from "ai-chat-bootstrap";
function UserProfile() {
const [user, setUser] = useState({
name: "Alice Johnson",
role: "admin",
plan: "pro"
});
// Share user profile with AI
useAIContext({
description: "User Profile",
value: user,
priority: 100,
});
return <div>...</div>;
}
Examples
Priority System
Higher priority context items are sent first to the AI:
// High priority - critical user info
useAIContext({ description: "User Auth", value: authData, priority: 100 });
// Medium priority - app state
useAIContext({ description: "App Settings", value: settings, priority: 80 });
// Low priority - metadata
useAIContext({ description: "Session Info", value: sessionData, priority: 60 });
Complete Implementation Example
Here’s a full example showing multiple context items:
"use client";
import React, { useState, useMemo } from "react";
import { ChatContainer, useAIChat, useAIContext } from "ai-chat-bootstrap";
export function AIContextDemo() {
const [userProfile, setUserProfile] = useState({
userId: "user-123",
name: "Alice Johnson",
email: "alice@example.com",
role: "admin",
plan: "pro",
notifications: true,
});
const [settings, setSettings] = useState({
theme: "dark",
language: "en",
maxMessages: 100,
autoSave: true,
});
// Static session info
const sessionInfo = useMemo(() => ({
sessionId: "session-" + Date.now(),
startedAt: new Date().toISOString(),
pageUrl: "/chat",
userAgent: navigator.userAgent,
}), []);
// Share context with AI - updates automatically when state changes
useAIContext({
description: "User Profile",
value: userProfile,
priority: 100,
});
useAIContext({
description: "App Settings",
value: settings,
priority: 80,
});
useAIContext({
description: "Session Info",
value: sessionInfo,
priority: 60,
});
const chat = useAIChat({
api: "/api/chat",
systemPrompt: "You are a helpful assistant with access to the user's profile, settings, and session information. Use this context to provide personalized responses."
});
return (
<div className="space-y-4">
{/* User Profile Widget */}
<div className="p-4 bg-card rounded-lg border">
<h3 className="text-lg font-semibold mb-3">User Profile</h3>
<div className="space-y-2">
<input
type="text"
value={userProfile.name}
onChange={(e) => setUserProfile(prev => ({...prev, name: e.target.value}))}
className="w-full px-3 py-2 border rounded-md"
placeholder="Name"
/>
<select
value={userProfile.role}
onChange={(e) => setUserProfile(prev => ({...prev, role: e.target.value}))}
className="w-full px-3 py-2 border rounded-md"
>
<option value="user">User</option>
<option value="admin">Admin</option>
<option value="moderator">Moderator</option>
</select>
</div>
</div>
{/* Settings Widget */}
<div className="p-4 bg-card rounded-lg border">
<h3 className="text-lg font-semibold mb-3">Settings</h3>
<div className="space-y-2">
<select
value={settings.theme}
onChange={(e) => setSettings(prev => ({...prev, theme: e.target.value}))}
className="w-full px-3 py-2 border rounded-md"
>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="auto">Auto</option>
</select>
<select
value={settings.language}
onChange={(e) => setSettings(prev => ({...prev, language: e.target.value}))}
className="w-full px-3 py-2 border rounded-md"
>
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
</select>
</div>
</div>
{/* Chat Interface */}
<ChatContainer
chat={chat}
header={{
title: "AI with Shared Context",
subtitle: "AI knows your profile and settings",
}}
ui={{ placeholder: "Ask about your profile or settings!" }}
/>
</div>
);
}
Backend Integration
The backend automatically receives context items in the request payload along with enrichedSystemPrompt
(which already embeds Tools / Context / Focus summaries and appends your original systemPrompt
if provided):
import { createAzure } from "@ai-sdk/azure";
import { convertToModelMessages, streamText } from "ai";
const azure = createAzure({
resourceName: process.env.AZURE_RESOURCE_NAME!,
apiKey: process.env.AZURE_API_KEY!,
apiVersion: process.env.AZURE_API_VERSION ?? "preview",
});
const model = azure(process.env.AZURE_DEPLOYMENT_ID!);
export async function POST(req: Request) {
const { messages, enrichedSystemPrompt, tools } = await req.json();
const result = await streamText({
model,
messages: [
{ role: "system", content: enrichedSystemPrompt },
...convertToModelMessages(messages),
],
tools,
});
return result.toUIMessageStreamResponse();
}
Note: Do NOT re-concatenate context data server-side. The client-built
enrichedSystemPrompt
already contains a standardized preamble plus conditional sections (Tools / Context / Focus) and then appends the originalsystemPrompt
verbatim.
Advanced Usage Patterns
Dynamic Context Updates
Context automatically updates when your state changes:
function TaskManager() {
const [currentTask, setCurrentTask] = useState(null);
// Context updates automatically when task changes
useAIContext({
description: "Active Task",
value: currentTask ? {
id: currentTask.id,
title: currentTask.title,
status: currentTask.status,
dueDate: currentTask.dueDate,
} : { message: "No active task" },
priority: 90,
});
return <div>...</div>;
}
Multiple Context Items from One Component
A single component can register multiple context items:
function Dashboard() {
const [user, setUser] = useState(userData);
const [projects, setProjects] = useState(projectsData);
const [notifications, setNotifications] = useState(notificationsData);
// User context
useAIContext({ description: "User", value: user, priority: 100 });
// Projects context
useAIContext({
description: "Projects",
value: {
activeProjects: projects.filter(p => p.status === 'active'),
totalCount: projects.length,
},
priority: 80,
});
// Notifications context
useAIContext({
description: "Notifications",
value: {
unreadCount: notifications.filter(n => !n.read).length,
latestNotification: notifications[0],
},
priority: 60,
});
return <div>...</div>;
}
Conditional Context
Only share context when certain conditions are met:
function ConditionalContext() {
const [user, setUser] = useState(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
// Only share user context when authenticated
useAIContext({
description: "User Authentication",
value: isAuthenticated && user ? {
id: user.id,
name: user.name,
permissions: user.permissions,
} : { authenticated: false },
priority: 100,
});
return <div>...</div>;
}
API Reference
- Hook: useAIContext
Best Practices
Preventing Re-render Loops
The useAIContext
hook follows the critical Zustand pattern to prevent infinite re-renders:
// ✅ Correct - Only include stable values in dependencies
useEffect(() => {
setContextItem(contextData);
return () => removeContextItem(id);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id, data, opts?.label, opts?.description, opts?.scope, opts?.priority]);
// ❌ Wrong - Including Zustand actions causes infinite loops
}, [id, data, setContextItem, removeContextItem]); // Don't do this!
Data Structure
Keep context data serializable and structured:
// ✅ Good - Clean, serializable data
useAIContext({ description: "User", value: {
id: user.id,
name: user.name,
role: user.role,
lastActive: user.lastActiveDate.toISOString(),
}, });
// ❌ Avoid - Functions, DOM nodes, complex objects
useAIContext({ description: "User", value: {
...user,
onClick: handleClick, // Function - not serializable
element: domRef.current, // DOM node - not serializable
complexObject: someClass, // Complex object - may not serialize
}});
Performance Optimization
Use useMemo
for expensive context computations:
function ExpensiveContext() {
const [rawData, setRawData] = useState([]);
const processedContext = useMemo(() => ({
summary: rawData.reduce((acc, item) => acc + item.value, 0),
categories: rawData.reduce((acc, item) => {
acc[item.category] = (acc[item.category] || 0) + 1;
return acc;
}, {}),
lastUpdated: new Date().toISOString(),
}), [rawData]);
useAIContext({ description: "Processed Data", value: processedContext, priority: 70 });
return <div>...</div>;
}
Security Considerations
Never share sensitive data in context:
// ✅ Safe - Only share necessary, non-sensitive data
useAIContext({ description: "User Profile", value: {
displayName: user.displayName,
role: user.role,
preferences: user.preferences,
}});
// ❌ Unsafe - Don't share sensitive information
useAIContext({ description: "User Auth", value: {
password: user.password, // Never share passwords
apiKeys: user.apiKeys, // Never share API keys
socialSecurity: user.ssn, // Never share PII
creditCard: user.paymentInfo, // Never share payment info
}});
Common Use Cases
User Profile Context
Share authenticated user information for personalized responses:
useAIContext({ description: "User Profile", value: userProfile, priority: 100 });
Application Settings
Share app configuration to tailor AI responses:
useAIContext({ description: "App Settings", value: appSettings, priority: 90 });
Current Page Context
Share information about the current page or view:
useAIContext({ description: "Page Context", value: {
route: router.pathname,
params: router.query,
title: document.title,
}, priority: 70 });
Form State
Share current form data for context-aware assistance:
useAIContext({ description: "Form State", value: {
formType: "user-registration",
completedFields: Object.keys(formData).filter(key => formData[key]),
validationErrors: errors,
}, priority: 80 });
Shopping Cart Context
Share e-commerce state for purchase assistance:
useAIContext({ description: "Shopping Cart", value: {
items: cart.items,
totalItems: cart.items.length,
totalValue: cart.total,
currency: "USD",
}, priority: 85 });
How Context Flows
- Component Registration: Components call
useAIContext()
with state data - Store Management: Context items are stored in a Zustand Map by ID
- Automatic Updates: When state changes, context is automatically updated
- Message Preparation: When sending messages,
serialize()
converts context to array - Priority Sorting: Context items are sorted by priority (higher first)
- Backend Delivery: Context is included in the request payload to your API route
- AI Integration: Your backend can access structured context for the AI model
Next
Continue to Focus Items →