Skip to content

Commit a706b8b

Browse files
authored
Update demo to match Next.js and Chat SDK best practices
Moved demo to latest Chat SDK Replace outdated Next.js patterns - Remove dynamic + ssr: false from app/page.js and replace with a direct import - Move Ably client creation into useEffect + useState in components/Chat.jsx to prevent new connections on every render - Add cleanup function that closes the Ably realtime connection on unmount - Migrate from next/head to the Next.js Metadata API Update README to reflect Ably Chat SDK usage, correct Node version, and fix outdated descriptions
2 parents 7516bd6 + f986d9c commit a706b8b

8 files changed

Lines changed: 107 additions & 80 deletions

File tree

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
20

README.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
> [!IMPORTANT]
2-
> This repository uses the Ably Pub/Sub approach for building chat apps. We now offer Ably Chat—a new family of SDKs and APIs that streamline development and manage realtime chat complexity for you. For a modern, easier way to create chat experiences, visit our [Ably Chat documentation](https://ably.com/docs/chat).
3-
4-
# Building a Realtime Chat App with Next.js, Ably, and Vercel
1+
# Building a realtime chat app with Next.js, Ably Chat, and Vercel
52

63
Live example at: <https://next-js-chat-app.vercel.app>
74

@@ -13,8 +10,8 @@ This is a demo chat application with [Next.js](https://nextjs.org/) using [Ably]
1310

1411
It demonstrates the use of:
1512

16-
- Pub/sub messaging
17-
- Ably's React Hooks
13+
- [Ably Chat SDK](https://github.com/ably/ably-chat-js) for messaging
14+
- [Ably Chat React hooks](https://ably.com/docs/chat/setup?lang=react) (`useMessages`, `useChatClient`)
1815
- Token authentication with Ably
1916

2017
## Tech stack
@@ -23,7 +20,7 @@ The project uses the following components:
2320

2421
- [Next.js](https://nextjs.org/) is a React framework from [Vercel](https://vercel.com/). It is used to build static web applications with server side rendering, serverless functions and seamless hosting. It's a framework that takes the React knowledge you already have, and puts some structure and conventions in place.
2522

26-
- [Ably](https://ably.com/) is realtime, pub/sub messaging platform with a suite of integrated services to deliver complete realtime functionality directly to end-users.
23+
- [Ably Chat](https://ably.com/docs/chat) is a set of SDKs built on top of Ably's realtime platform, designed for building chat experiences with minimal setup.
2724

2825
- [Vercel](https://vercel.com/) is a hosting platform, built from the ground up to host Next.js apps, and Serverless Functions with them.
2926

@@ -34,7 +31,7 @@ The project uses the following components:
3431
![The UI of the chat app we'll build. It is a window with speech bubbles for text.](https://cdn.glitch.com/0cb30add-c9ef-4c00-983c-e12deb0d4080%2Fchatapp.png?v=1612279601157)
3532
*The UI of the app we'll build with this walkthrough*
3633

37-
We'll build a realtime chat app that runs in the browser. It will be built upon the Next.js [create-next-app](https://nextjs.org/docs/api-reference/create-next-app) template, it will contain a React component which will use Ably to send and receive messages. We'll also write a Next.js serverless function which will be used to connect to Ably.
34+
We'll build a realtime chat app that runs in the browser. It will be built upon the Next.js [create-next-app](https://nextjs.org/docs/api-reference/create-next-app) template, it will contain a React component which will use the Ably Chat SDK to send and receive messages. We'll also write a Next.js [Route Handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) which will be used to authenticate with Ably.
3835

3936
## Building & running locally
4037

@@ -44,7 +41,7 @@ In order to build and deploy this app, you will need:
4441

4542
- **An Ably account** for sending messages: [Create an account with Ably for free](https://ably.com/signup).
4643
- **A Vercel Account** for hosting on production: [Create an account with Vercel for free](https://vercel.com/signup).
47-
- **Node 16** or greater: [Install Node](https://nodejs.org/en/).
44+
- **Node 20** or greater: [Install Node](https://nodejs.org/en/).
4845

4946
You'll also need an API key from Ably to authenticate with the Ably Service. To get an API key, once you have [created an Ably account](https://ably.com/signup):
5047

app/layout.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import './globals.css';
22

33
export const metadata = {
4-
title: 'Next.js',
5-
description: 'Generated by Next.js',
4+
title: 'Realtime Chat App with Ably, NextJS and Vercel',
5+
description: 'A demo chat application with Next.js using Ably Chat',
6+
icons: {
7+
icon: { url: 'https://static.ably.dev/motif-red.svg?nextjs-vercel', type: 'image/svg+xml' },
8+
},
69
};
710

811
export default function RootLayout({ children }) {

app/page.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
1-
import Head from 'next/head';
2-
import dynamic from 'next/dynamic';
3-
4-
const Chat = dynamic(() => import('../components/Chat'), {
5-
ssr: false,
6-
});
1+
import Chat from '../components/Chat';
72

83
export default function Home() {
94
return (
105
<div className="container">
11-
<Head>
12-
<title>Realtime Chat App with Ably, NextJS and Vercel</title>
13-
<link rel="icon" href="https://static.ably.dev/motif-red.svg?nextjs-vercel" type="image/svg+xml" />
14-
</Head>
15-
166
<main>
177
<h1 className="title">Next.js Chat Demo</h1>
188
<Chat />

components/Chat.jsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
'use client';
22

3+
import { useEffect, useState } from 'react';
34
import * as Ably from 'ably';
45
import { ChatClient } from '@ably/chat';
56
import { ChatClientProvider, ChatRoomProvider } from '@ably/chat/react';
67
import ChatBox from './ChatBox.jsx';
78

8-
const roomOptions = {
9-
history: { limit: 50 },
10-
};
9+
const roomOptions = {};
1110

1211
export default function Chat() {
13-
const realtimeClient = new Ably.Realtime({ authUrl: '/api' });
14-
const chatClient = new ChatClient(realtimeClient);
12+
const [chatClient, setChatClient] = useState(null);
13+
14+
useEffect(() => {
15+
const realtimeClient = new Ably.Realtime({ authUrl: '/api' });
16+
const client = new ChatClient(realtimeClient);
17+
setChatClient(client);
18+
return () => {
19+
realtimeClient.close();
20+
};
21+
}, []);
22+
23+
if (!chatClient) return <div>Loading...</div>;
1524

1625
return (
1726
<ChatClientProvider client={chatClient}>
18-
<ChatRoomProvider id="chat-demo" options={roomOptions}>
27+
<ChatRoomProvider name="chat-demo" options={roomOptions}>
1928
<ChatBox />
2029
</ChatRoomProvider>
2130
</ChatClientProvider>

components/ChatBox.jsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,14 @@ export default function ChatBox() {
1010
const [messages, setMessages] = useState([]);
1111
const messageTextIsEmpty = messageText.trim().length === 0;
1212

13-
const { send: sendMessage } = useMessages({
13+
const { sendMessage } = useMessages({
1414
listener: (payload) => {
1515
const newMessage = payload.message;
1616
setMessages((prevMessages) => {
17-
if (prevMessages.some((existingMessage) => existingMessage.isSameAs(newMessage))) {
17+
if (prevMessages.some((existingMessage) => existingMessage.serial === newMessage.serial)) {
1818
return prevMessages;
1919
}
20-
21-
const index = prevMessages.findIndex((existingMessage) => existingMessage.after(newMessage));
22-
23-
const newMessages = [...prevMessages];
24-
if (index === -1) {
25-
newMessages.push(newMessage);
26-
} else {
27-
newMessages.splice(index, 0, newMessage);
28-
}
29-
return newMessages;
20+
return [...prevMessages, newMessage].sort((a, b) => (a.serial < b.serial ? -1 : b.serial < a.serial ? 1 : 0));
3021
});
3122
},
3223
});

0 commit comments

Comments
 (0)