Updating My React Site: Integrating PromptSpark and SignalR

Enhancing My React Project with Real-Time Chat Feature

As I work on the project, GitHub pages will be the place to view the application: ReactSparkPortfolio on GitHub Pages

Demonstration: The Joke Explainer in Action

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.

Original Project Setup with Vite

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.

Integrating PromptSpark with SignalR

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

Reflections on Modular Development with React

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.

A complete guide to building a real-time chat app with TypeScript, SignalR, and Markdown rendering

Setting Up the Project

I started with my Portfolio project using Vite for fast development builds, along with TypeScript and React. For this effor, 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 for Real-Time Messaging

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 with React

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>
);
Integrating a 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
  }
};
Streaming Responses in Real Time

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);
});
Rendering Markdown with react-markdown

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>;
Handling Incremental Loading in the Chat

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>}
/>
Managing Errors and Fixing Styling Issues

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.

Finalizing with Bootstrap Icons and Styles

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.