Building Real-Time Chat
Enhancing Real-Time Interactions with Adaptive Technologies
Explore how to build a real-time React chat application integrated with SignalR for live messaging and Markdown for streaming content rendering. Learn step-by-step integration and how these technologies can enhance interactive user experiences.
Live Demonstration
Project Overview
In my ongoing journey to learn React and TypeScript, I have been enhancing the site I built. This post dives into integrating the site with my PromptSpark project by linking it to the existing SignalR implementation.
Key Technologies
- React & TypeScript
- SignalR Hub
- Markdown Streaming
- Vite Development
Development Process
Initially, I built my React site with Vite to benefit from fast development speeds, simplified setup, and compatibility with TypeScript. Starting with the basics, I created a functional and minimal site that allowed me to explore React's component-based structure, state management, and simple user interactions. Vite's zero-config setup was a great advantage, allowing me to start coding immediately with hot-reloading and seamless builds.
The goal with this update was to connect my site to PromptSpark, a tool I built to provide custom prompts for applications. I wanted a chat bot experience with PromptSpark variants. To achieve this, I leveraged the existing SignalR hub created to facilitate two-way communication between users and the PromptSpark system. SignalR's integration allows for real-time prompt suggestions and dynamic responses, creating a more interactive user experience.
By building on the foundation of my original site, I could focus on integrating these new features without needing a major overhaul. I took advantages of modular development with React and showcased the power of TypeScript and Vite for rapid development, even as requirements grow.
Complete Implementation Guide
I started with my Portfolio project using Vite for fast development builds, along with TypeScript and React. For this effort, I needed to add integration with SignalR for real-time messaging and `react-markdown` for rendering Markdown content.
npm install @microsoft/signalr react-markdown
Connecting to SignalR
One of the first tasks was configuring SignalR to enable real-time, two-way communication between the server and the client. In my `Chat.tsx` file, I created a `HubConnection` to connect to the server and added an event listener to receive messages in real time.
import * as signalR from "@microsoft/signalr";
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.build();
connection.on("ReceiveMessage", (user, message) => {
setMessages((prev) => [...prev, { user, message }]);
});
Designing the Chat UI
The UI needed to be straightforward and mobile-responsive, so I used Bootstrap classes to quickly create the layout. I structured it with input fields for username and messages, a join button, and a display area for conversation-style messages.
return (
<div className="chat-container">
<input type="text" placeholder="Username" onChange={setUser} />
<input type="text" placeholder="Message" onChange={setMessage} />
<button onClick={sendMessage}>Join Chat</button>
<div className="messages-display">{messages.map(...)}</div>
</div>
);
Bot with Customizable Tones
I wanted the chat app to feature a bot with customizable tones, such as helpful, funny, or pirate-themed responses. I achieved this by passing a `variantName` prop to customize each bot's tone, making it easy for users to choose a specific bot personality.
const BotResponse = ({ variantName }: { variantName: string }) => {
switch(variantName) {
case "pirate":
return "Arr! Ye message received!";
case "helpful":
return "How can I assist you today?";
// other variants
}
};
Advanced Features
Streaming Responses
To achieve a real-time, streaming experience, I implemented logic to accumulate bot responses in chunks, displaying the content as it streamed in. Using a `streamingMessage` state, the bot's responses would appear incrementally as data continued streaming from SignalR.
const [streamingMessage, setStreamingMessage] = useState("");
connection.on("StreamMessage", (chunk) => {
setStreamingMessage((prev) => prev + chunk);
});
Markdown Rendering
For a richer text experience, I used `react-markdown` to render bot responses with Markdown formatting. This allowed the bot to send formatted messages, including bold text, lists, and links.
import ReactMarkdown from "react-markdown";
<ReactMarkdown>{markdownContent}</ReactMarkdown>;
Incremental Loading
I added incremental message updates with the `FlatList` component's `ListFooterComponent`, allowing the UI to update as new Markdown chunks streamed in. This setup provided a seamless, real-time experience, with messages appearing as soon as they arrived.
<FlatList
data={messages}
renderItem={({ item }) => <ReactMarkdown>{item}</ReactMarkdown>}
ListFooterComponent={<div>{streamingMessage}</div>}
/>
Error Management & Styling
Throughout development, I encountered TypeScript errors, especially with type mismatches in components. I solved these by refining types and ensuring all components aligned with TypeScript and React standards. Additionally, I removed redundant CSS by relying more on Bootstrap utilities for a cleaner, consistent style.
For the final touches, I added Bootstrap Icons and styled components to keep the interface cohesive. This approach streamlined the code and enhanced user experience with clean, responsive visuals.
Conclusion
Building this chat app provided a deeper understanding of real-time communication, content streaming, and Markdown rendering in a React and TypeScript environment. It involved leveraging SignalR for bidirectional messaging, handling Markdown in real time, and creating dynamic bot personalities for a more engaging user experience.