Skip to main content

Overview

The ChatContext provides centralized state management for the currently active chat conversation in the CicloVital application. It automatically persists the selected chat to localStorage for continuity across sessions.

Context Shape

interface ChatContextValue {
  currentChat: Chat | null;
  setCurrentChat: (chat: Chat | null) => void;
}

Properties

currentChat
Chat | null
The currently selected chat conversation object, or null if no chat is selected.
setCurrentChat
function
Function to update the current chat. Pass null to deselect.
(chat: Chat | null) => void

Provider Component

ChatProvider

Wraps your application to provide chat context to all child components.
import ChatProvider from './contexts/ChatProvider';

function App() {
  return (
    <ChatProvider>
      {/* Your app components */}
    </ChatProvider>
  );
}

Features

  • Automatic Persistence: Current chat is automatically saved to localStorage
  • Session Recovery: Loads the last selected chat from localStorage on initialization
  • Safe Storage: Includes error handling for localStorage operations
  • Deselection Support: Removes data from localStorage when chat is set to null

Usage

Consuming the Context

import { useContext } from 'react';
import ChatContext from './contexts/ChatContext';

function ChatWindow() {
  const { currentChat, setCurrentChat } = useContext(ChatContext);

  if (!currentChat) {
    return <p>Select a chat to start messaging</p>;
  }

  return (
    <div>
      <h2>Chat with {currentChat.participantName}</h2>
      <MessageList messages={currentChat.messages} />
    </div>
  );
}

Selecting a Chat

function ChatList({ chats }) {
  const { setCurrentChat } = useContext(ChatContext);

  const handleChatSelect = (chat) => {
    setCurrentChat(chat);
  };

  return (
    <ul>
      {chats.map(chat => (
        <li key={chat.id} onClick={() => handleChatSelect(chat)}>
          {chat.participantName}
        </li>
      ))}
    </ul>
  );
}

Clearing the Selected Chat

function ChatHeader() {
  const { currentChat, setCurrentChat } = useContext(ChatContext);

  const handleClose = () => {
    setCurrentChat(null);
  };

  return (
    <div>
      <h3>{currentChat?.participantName}</h3>
      <button onClick={handleClose}>Close Chat</button>
    </div>
  );
}

Checking if a Chat is Active

function ChatListItem({ chat }) {
  const { currentChat } = useContext(ChatContext);
  
  const isActive = currentChat?.id === chat.id;

  return (
    <div className={isActive ? 'active' : ''}>
      {chat.participantName}
    </div>
  );
}

Implementation Details

Source Files

  • src/contexts/ChatContext.js - Context definition
  • src/contexts/ChatProvider.jsx - Provider implementation

localStorage Key

The context stores chat data under the key "chat" in localStorage.

Initial State

On mount, the provider attempts to load the current chat from localStorage. If no data exists or parsing fails, it defaults to null.
const [currentChat, setCurrentChat] = useState(() => safeGet("chat", null));

Best Practices

Use optional chaining (currentChat?.property) when accessing chat properties to safely handle the null state.
The entire chat object is persisted to localStorage. For large chat histories, consider storing only the chat ID and fetching full details from a server.

Common Patterns

Auto-selecting First Chat

function ChatApp() {
  const { currentChat, setCurrentChat } = useContext(ChatContext);
  const [chats, setChats] = useState([]);

  useEffect(() => {
    // Load chats from API
    loadChats().then(loadedChats => {
      setChats(loadedChats);
      // Auto-select first chat if none is selected
      if (!currentChat && loadedChats.length > 0) {
        setCurrentChat(loadedChats[0]);
      }
    });
  }, []);

  return <ChatInterface />;
}

Build docs developers (and LLMs) love