React에서 실시간 메시징 앱을 만드는 PubNub 및 Pusher

DDD
풀어 주다: 2024-09-13 22:18:02
원래의
552명이 탐색했습니다.

실시간 데이터는 요즘 최신 애플리케이션의 핵심 요소 중 하나입니다. 양방향 정보를 보낼 수 있는 시스템을 갖추면 다양한 정보를 최신 상태로 유지할 수 있습니다. 이러한 예로는 메시징 애플리케이션, 재무 데이터에 사용되는 대시보드용 데이터 분석, 증강 및 가상 애플리케이션에 사용되는 헤드업 디스플레이(HUD)가 포함될 수 있습니다. 항공기를 조종하는 전투기 조종사나 Apple Vision Pro 헤드셋을 사용하는 일반 소비자와 같습니다. 이 기술의 활용 사례는 무궁무진합니다.

일반적인 IM 애플리케이션에 대해 이야기할 때, 누군가와 실시간으로 대화할 수 있다는 것은 수많은 독특한 가능성의 문을 열어줍니다. 우리의 세계는 이러한 새로 발견된 기능의 결과로 더욱 더 연결되었습니다. 오늘 기사에서는 실시간 메시징 애플리케이션을 구축하면서 메시징에 대한 모든 것을 배울 것입니다. 애플리케이션은 Pusher와 PubNub라는 두 가지 실시간 애플리케이션 플랫폼에 연결할 수 있습니다.

우리 애플리케이션은 WhatsApp 및 Telegram 애플리케이션의 기본 베어본 버전과 매우 유사합니다. 하나 이상의 웹 브라우저나 브라우저 탭을 열 수 있으며 이를 통해 여러 사용자로 로그인할 수 있는 기능이 제공됩니다. 이렇게 하면 실제 채팅 애플리케이션처럼 두 명 이상의 사용자 간의 그룹 채팅을 테스트할 수 있습니다.

아래에서 기본 대시보드의 모습을 볼 수 있습니다. 두 버전의 메시지 앱으로 이동할 수 있는 버튼이 있습니다.

PubNub vs Pusher creating a realtime messaging app in React

이 스크린샷에서 우리 앱의 PubNub 버전이 어떻게 보이는지 확인할 수 있습니다. 파란색 헤더로 표시됩니다:
PubNub vs Pusher creating a realtime messaging app in React

Pusher 버전에는 녹색 머리글이 있으며 이를 통해 두 머리글의 차이점을 시각적으로 알 수 있습니다.
PubNub vs Pusher creating a realtime messaging app in React

자, 빠른 소개가 완료되었으므로 이제 서로 어떻게 대조되는지 확인하면서 훨씬 더 철저하게 살펴볼 수 있습니다. 메시징 애플리케이션의 코드베이스는 내 GitHub(https://github.com/andrewbaisden/realtime-chat-app)에서 찾을 수 있습니다.

전제 조건

시작하기 전에 필수 구성 요소를 살펴보고 시작하기 전에 모든 설정이 완료되었는지 확인하세요.

  • Node와 npm이 설치되었습니다.
  • Visual Studio Code처럼 설치된 IDE
  • PubNub 계정
  • Pusher 계정

PubNub 대 푸셔

두 플랫폼 모두 공통점이 많지만 쉽게 구별할 수 있는 눈에 띄는 차이점이 있습니다. 주요한 것 중 하나는 아키텍처가 동일하지 않다는 사실입니다.

아키텍처의 차이점

PubNub의 경우 데이터와 메시지 스트리밍을 관리할 수 있는 클라우드 플랫폼입니다. 전 세계적으로 이용 가능한 우수한 서비스 가용성만큼 대기 시간이 매우 짧습니다. 확장 및 인프라는 플랫폼에서 잘 처리되므로 개발자는 프로젝트가 무엇인지에 대해 자유롭게 작업할 수 있습니다.

이제 Pusher에서는 자체 호스팅 및 클라우드 호스팅 등 다양한 배포 옵션을 제공합니다. 자체 호스팅을 사용하는 경우 Pusher는 사용자 정의 하드웨어나 소프트웨어에서 실행될 수 있으므로 많은 자유를 누릴 수 있습니다. 클라우드 호스팅 솔루션의 경우 PubNub과 유사한 서비스를 기대할 수 있습니다.

API와 SDK 비교

기능을 비교해 보면 둘 다 다양한 프로그래밍 언어에서 지원되는 SDK와 라이브러리를 제공한다는 것을 알 수 있습니다. 여기에는 JavaScript, Python, Java, Swift, Ruby 등이 포함됩니다. 채널은 두 플랫폼 모두에서 사용할 수 있으며 이를 통해 다양한 데이터 스트림을 게시하고 구독할 수 있습니다. 현재 상태는 또 다른 옵션이며 이를 통해 우리가 설정한 다양한 채널에서 모든 사용자의 온라인 및 오프라인 상태를 실시간으로 확인할 수 있습니다. 메시지 기록과 관련해서는 비슷한 내용이 있으며 푸시 알림에도 동일하게 적용됩니다.

또 다른 좋은 측면은 기능이 풍부하고 문서가 매우 쉽게 학습하고 제공되는 다양한 특징을 빠르게 익힐 수 있다는 점입니다. 아래에서 해당 문서를 찾을 수 있습니다.

PubNub 문서: PubNub
푸셔 문서: 푸셔

React를 사용하여 실시간 메시징 앱 구현

지원서 작성 시간입니다! 먼저 PubNub 및 Pusher에 계정이 있는지 확인하세요. 이제 두 플랫폼 모두에서 계정을 만드는 과정을 신속하게 진행할 것이므로 아직 계정을 만들지 않았다면 계속 진행하세요.

Erstellen eines Kontos bei PubNub

Beginnen Sie mit PubNub. Rufen Sie die Startseite der Website auf und klicken Sie auf die Schaltfläche oben rechts, um es kostenlos zu testen, wie unten gezeigt.

PubNub vs Pusher creating a realtime messaging app in React

Sie sollten nun die Registrierungsseite sehen, also fahren Sie fort und verwenden Sie das Formular, um Ihr Konto zu erstellen.

PubNub vs Pusher creating a realtime messaging app in React

Okay, jetzt sollte mit Ihrem erstellten Konto Zugriff auf das Dashboard möglich sein. Gehen Sie über das Menü zum Abschnitt „Keysets“ und suchen Sie dort nach Ihrer App und ihrem Keyset. Dies ist auch der Teil, in dem Sie eine App erstellen sollten, falls noch keine vorhanden ist.

Ihre API-Schlüssel sollten jetzt sichtbar sein. Stellen Sie daher sicher, dass die Optionen „Präsenz“ und „Persistenz“ aktiviert sind, da wir dies benötigen, um Benutzer und Daten zu verfolgen.

PubNub vs Pusher creating a realtime messaging app in React

Erstellen Sie ein Konto bei Pusher

Okay, wir sind mit unserem PubNub-Konto fertig, jetzt können wir an unserem Pusher-Konto arbeiten. Gehen Sie wie zuvor auf die Website und klicken Sie oben rechts auf der Seite auf die Schaltfläche „Anmelden“.

PubNub vs Pusher creating a realtime messaging app in React

Verwenden Sie nun auf dem folgenden Bildschirm das Formular, um ein Konto zu erstellen, wie Sie es hier sehen.

PubNub vs Pusher creating a realtime messaging app in React

Es muss ein Kanal erstellt werden. Wählen Sie dazu auf der Dashboard-Seite die Schaltfläche „Verwalten“ aus.

PubNub vs Pusher creating a realtime messaging app in React
Erstellen Sie auf der nächsten Seite, die der Kanalbildschirm sein sollte, eine App, indem Sie die Schaltfläche „App erstellen“ verwenden, wie in diesem Screenshot gezeigt.

PubNub vs Pusher creating a realtime messaging app in React

Jetzt können wir mit dem Formular fortfahren und wie Sie in diesem Beispiel sehen können, sollte die Konfiguration maßgeschneidert für Ihren Anwendungsfall sein.

PubNub vs Pusher creating a realtime messaging app in React

Sobald diese Phase abgeschlossen ist, sollte die Kanalseite so angezeigt werden, wie sie hier ist.
PubNub vs Pusher creating a realtime messaging app in React
Klicken Sie im Seitenleistenmenü auf „App Keys“ und Sie erhalten dann Zugriff auf die API-Schlüssel, die Sie später benötigen.

PubNub vs Pusher creating a realtime messaging app in React

Super, die Kontoeinrichtungsphase ist nun abgeschlossen. Im nächsten Abschnitt beginnen wir mit dem Code für unsere App. Der erste Schritt besteht darin, die Projektarchitektur mit den Ordnern usw. zu erstellen. Ich habe ein Kopier- und Einfügeskript für die Befehlszeile erstellt, damit wir nicht alle Befehle manuell schreiben müssen. Erstellen Sie zunächst ein Projekt mit dem Namen „realtime-chat-app“ auf Ihrem Computer und gehen Sie dann über die Befehlszeile zum Speicherort.

Einrichten der React-Anwendung

Verwenden Sie Next.js, um ein Projekt zu erstellen, und verwenden Sie dann das Shell-Skript, um das Projekt einzurichten.

Wir beginnen mit der Ausführung dieses Befehls, um ein Next.js-Projekt zu erstellen:

npx create-next-app client
로그인 후 복사

Jetzt ist es wichtig, auf dem Konfigurationsbildschirm Tailwind CSS und den App Router auszuwählen, da wir diese Optionen in diesem Projekt benötigen.

Hier ist das Shell-Skript zum Erstellen der Dateien und Ordner und zum Installieren der Abhängigkeiten. Führen Sie es einfach im selben Ordner aus. Es wird automatisch in den Client-Ordner kopiert. Wenn Sie sich bereits im Client-Ordner befinden, können Sie die erste Zeile im Skript weglassen.

cd client
npm install @pubnub/react-chat-components axios pubnub pubnub-react pusher pusher-js
touch .env.local
cd src/app
mkdir components pubnub pusher
touch components/ChatInterface.js components/ChatMessage.js components/ChatPubNub.js components/ChatPusher.js components/DashboardButton.js components/Header.js components/UserLogin.js pubnub/page.js pusher/page.js
cd ../../..
mkdir server
cd server
npm init -y
npm install express cors pusher dotenv
touch index.js .env
cd ..
로그인 후 복사

Hier ist viel los, also schauen wir mal, was dieses Skript macht:

  • Installieren der Abhängigkeiten für unser Projekt, das die Pakete sowie die PubNub- und Pusher-Pakete enthält
  • Erstellen von Umgebungsvariablendateien für unsere API-Schlüssel
  • Erstellen der Dateien, Ordner und Komponenten für unsere gesamte App
  • Einrichten eines Backend-Servers, den Pusher für den API-Zugriff benötigt
  • Erstellen der Serverdateien für Routing- und Logikzwecke

Sehen Sie sich diesen Screenshot an. So sollte unser Projekt in Ihrer IDE aussehen:

PubNub vs Pusher creating a realtime messaging app in React

The hard work is done that build script did most of the work we just have to add the code to the files.

Right our first file is the globals.css file so clear all the code in that file and replace it with what is shown here:

@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  background-color: rgb(15 23 42);
}
로그인 후 복사

Code cleanup has been done in this file and now we have a background colour for our application.

Onto the layout.css file. Continuing from what we just did replace all the code with this new code:

import { Ubuntu } from 'next/font/google';
import './globals.css';

const ubuntu = Ubuntu({
  subsets: ['latin'],
  weight: ['300', '400', '500', '700'],
});

export const metadata = {
  title: 'Realtime Chat App',
  description: 'Generated by create next app',
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={ubuntu.className}>{children}</body>
    </html>
  );
}
로그인 후 복사

Ubuntu is now the default font in our application.

All thats left in this section is to replace all of the code in our next.config.mjs file with this code:

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        hostname: 'res.cloudinary.com',
      },
    ],
  },
};

export default nextConfig;
로그인 후 복사

Cloudinary was added as an image host so now we can use it throughout our app.

And with that the project setup phase is done so in the next section we will work on the main files for our codebase. First we will do PubNub and then we will do Pusher.

Integrating PubNub

The initilisation and configuration part will be the first one to tackle. You must sign into your PubNub account, and find the application you made at the start. Locate your Keysets as well as the Publish and Subscribe Keys. Now put them inside of the .env.local file in the project.

Here is an example of where they should be put:

NEXT_PUBLIC_PUBNUB_PUBLISH_KEY=your-publish-key
NEXT_PUBLIC_PUBNUB_SUBSCRIBE_KEY=your-subscribe-key
로그인 후 복사

Time to add some code to our components/ChatPubNub.js file, and this is the file where we can find the main code for subscribing to channels, handling the presence and publishing our message.

Put the code you see here into the components/ChatPubNub.js file:

import { useState, useEffect, useRef } from 'react';
import PubNub from 'pubnub';
import ChatInterface from './ChatInterface';

export default function ChatPubNub({ activeUser }) {
  const [chats, setChats] = useState([]);
  const [count, setCount] = useState(1);
  const bottomRef = useRef(null);

  let pubnub;
  const channelName = 'presence-chatroom';

  useEffect(() => {
    pubnub = new PubNub({
      publishKey: process.env.NEXT_PUBLIC_PUBNUB_PUBLISH_KEY,
      subscribeKey: process.env.NEXT_PUBLIC_PUBNUB_SUBSCRIBE_KEY,
      uuid: activeUser,
    });

    pubnub.addListener({
      message: (messageEvent) => {
        const chat = messageEvent.message;
        setChats((prevChats) => [...prevChats, chat]);
      },
    });

    const presenceChannelName = `${channelName}-pnpres`;

    pubnub.subscribe({
      channels: [channelName],
      withPresence: true,
      presenceChannels: [presenceChannelName],
    });

    const scrollToBottom = () => {
      bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
    };

    scrollToBottom();

    return () => {
      pubnub.unsubscribeAll();
    };
  }, [chats, activeUser, count]);

  const handleKeyUp = (evt) => {
    const value = evt.target.value;
    if (evt.keyCode === 13 && !evt.shiftKey) {
      const chat = { user: activeUser, message: value, timestamp: +new Date() };
      evt.target.value = '';
      pubnub.publish({
        channel: channelName,
        message: chat,
      });
    }
  };

  return activeUser ? (
    <>
      <ChatInterface
        activeUser={activeUser}
        count={count}
        chats={chats}
        handleKeyUp={handleKeyUp}
        bottomRef={bottomRef}
      />
    </>
  ) : null;
}
로그인 후 복사

Here is a quick explanation of what our code does in this file. We can do subscriptions to channels, publish messages to different channels as well as handle the overall presence information. With these capabilities our app will function a lot like a group chat and with presence switched on we can see how many users are online in real-time.

We can work on our next file now which is the components/ChatInterface.js so add this code to it:

import ChatMessage from './ChatMessage';

export default function ChatInterface({
  activeUser,
  count,
  chats,
  handleKeyUp,
  bottomRef,
}) {
  return (
    <div className="flex">
      <aside className="w-64 min-w-64 bg-slate-800 p-2">
        <h1 className="text-lg text-white">Chats</h1>
        <div className="flex justify-between mt-2">
          <div className="flex">
            <div className="rounded-full bg-slate-100 h-10 w-10 mr-2"></div>
            <div className="text-sm">
              <p className="text-white">John</p>
              <p className="text-slate-400">Hello world</p>
            </div>
          </div>
          <div className="text-sm text-slate-400">Friday</div>
        </div>
      </aside>
      <section className="grow">
        <div className="bg-zinc-800 p-2">
          <div className="flex">
            <div className="rounded-full bg-slate-100 h-10 w-10 mr-2"></div>
            <div>
              <h1 className="text-2xl text-white">{activeUser}</h1>
              <span className="text-gray-300">users online: {count}</span>
            </div>
          </div>
        </div>
        <div className="bg-zinc-900 p-2 overflow-y-auto h-80 max-h-80 text-white">
          {chats.map((chat, index) => {
            const previous = Math.max(0, index - 1);
            const previousChat = chats[previous];
            const position = chat.user === activeUser ? 'right' : 'left';
            const isFirst = previous === index;
            const inSequence = chat.user === previousChat.user;
            const hasDelay =
              Math.ceil(
                (chat.timestamp - previousChat.timestamp) / (1000 * 60)
              ) > 1;
            return (
              <div key={index}>
                {(isFirst || !inSequence || hasDelay) && (
                  <div>
                    <span>{chat.user || 'Anonymous'}</span>
                  </div>
                )}

                <ChatMessage message={chat.message} position={position} />
              </div>
            );
          })}
          <div ref={bottomRef} />{' '}
        </div>
        <div className="w-full bg-zinc-800 p-2">
          <textarea
            onKeyUp={handleKeyUp}
            placeholder="Enter a message"
            className="w-full block rounded mt-2 mb-2 p-2 text-white bg-zinc-600"
          ></textarea>
        </div>
      </section>
    </div>
  );
}
로그인 후 복사

Our component displays the UI for our messaging chat interface. There is a section for messaging, sending messages and a sidebar, which could hold users when they are in the group.

The next component is for the components/ChatMessage.js file and this has our chat message interface.

Add this code to the file:

export default function ChatMessage({ message }) {
  return (
    <div>
      <div className="mt-4 mb-4">
        <span className="bg-zinc-600 p-2 rounded">{message}</span>
      </div>
    </div>
  );
}
로그인 후 복사

Chat bubbles should become possible thanks to this component whenever we use the chat to send messages to users.

Dashboard buttons is what we require next so add this code to our components/DashboardButton.js file:

import Link from 'next/link';
import Image from 'next/image';

export default function DashboardButton({ url, img, alt }) {
  return (
    <>
      <Link href={url}>
        <div className="rounded mr-4 bg-slate-50 hover:bg-slate-200 h-96 w-96 text-center flex items-center justify-center drop-shadow-lg uppercase">
          <Image src={img} height={200} width={200} alt={alt} />
        </div>
      </Link>
    </>
  );
}
로그인 후 복사

We can now easily navigate between the PubNub and Pusher versions of our real-time messaging chat app using these reusable buttons.

Ok the navigation component is next and this is for our main header. Put this code in our file at components/Header.js:

import Link from 'next/link';

export default function Header() {
  return (
    <>
      <nav className="bg-white flex justify-around p-8 mb-4 font-bold">
        <Link href={'/'}>Dashboard</Link>
        <Link href={'/pusher'}>Pusher Chat App</Link>
        <Link href={'/pubnub'}>PubNub Chat App</Link>
      </nav>
    </>
  );
}
로그인 후 복사

All our page routes are easily able to be navigated using this header component which has page links.

The login screen is next and this is the code our file at components/UserLogin.js desires:

import { useState } from 'react';
import ChatPubNub from '../components/ChatPubNub';
import ChatPusher from '../components/ChatPusher';

export default function UserLogin({ bgColor, appName }) {
  const [user, setUser] = useState(null);

  const handleKeyUp = (evt) => {
    if (evt.keyCode === 13) {
      const newUser = evt.target.value;
      setUser(newUser);
    }
  };
  return (
    <>
      <main>
        <div>
          <section>
            <div className={`p-4 ${bgColor} text-slate-100`}>
              <span>
                {user ? (
                  <span className="flex justify-between text-white">
                    <span>
                      {user} <span>is online</span>
                    </span>
                    <span>{appName}</span>
                  </span>
                ) : (
                  <span className="text-2xl text-white">
                    What is your name?
                  </span>
                )}
              </span>
              {!user && (
                <input
                  type="text"
                  onKeyUp={handleKeyUp}
                  autoComplete="off"
                  className="w-full block rounded mt-2 mb-2 p-2 text-black"
                />
              )}
            </div>
          </section>
          {appName === 'PubNub Chat' ? (
            <section>{user && <ChatPubNub activeUser={user} />}</section>
          ) : (
            <section>{user && <ChatPusher activeUser={user} />}</section>
          )}
        </div>
      </main>
    </>
  );
}
로그인 후 복사

Its a pretty straightforward login screen component whereby a user can choose a name and then they get redirected to the messaging app. There is logic to check which app a user is using and it automatically sends the user to the right chat interface for that version of the app.

Lets do the pubnub/page.js route file now and add this code to it:

'use client';
import Header from '../components/Header';
import UserLogin from '../components/UserLogin';

export default function PubNub() {
  return (
    <div>
      <Header />
      <UserLogin bgColor={'bg-sky-800'} appName={'PubNub Chat'} />
    </div>
  );
}
로그인 후 복사

We can find the main page route for the PubNub version messaging app.

Lastly we must add code to our page.js file in the root folder to complete our application so like before just replace the code with what we have written here:

'use client';
import DashboardButton from './components/DashboardButton';

export default function Home() {
  return (
    <>
      <div className="h-screen flex justify-center items-center">
        <div className="text-center">
          <h1 className="mb-4 text-white text-4xl">Choose a messaging app</h1>
          <div className="grid gap-2 lg:grid-cols-2 md:grid-cols-1 sm:grid-cols-1">
            <DashboardButton
              url={'/pusher'}
              img={
                'https://res.cloudinary.com/d74fh3kw/image/upload/v1715187329/pusher-logo_u0gljx.svg'
              }
              alt="Pusher Logo"
            />
            <DashboardButton
              url={'/pubnub'}
              img={
                'https://res.cloudinary.com/d74fh3kw/image/upload/v1715189173/pubnub-logo-vector_olhbio.png'
              }
              alt="PubNub Logo"
            />
          </div>
        </div>
      </div>
    </>
  );
}
로그인 후 복사

Our main dashboard link can be found here which has the buttons for our PubNub and Pusher version of our application.

The PubNub messaging part of our application should be good to go now! Just cd into the client folder if you have not done so already and start the application with the usual Next.js run command:

npm run dev
로그인 후 복사

Its worth mentioning that the Pusher part of our application is not going to work yet as we must complete the integrations in the upcoming section. To use the PubNub app go to the login screen, enter a name and hit the enter button and then you will see the messenger chat application screen. You can see your online status and the sidebar has a hard-coded user which is just an example.

To make the application more interactive open more browser tabs or browser windows and sign in with more users. Having a real-time group chat is now possible just like any other messaging app you are familiar with.

In the next section we shall get Pusher up and working.

Integrating Pusher

This section will take less time because we get to reuse a lot of the components we used in the earlier sections. The difference this time around is that Pusher will need to connect to our backend server to work.

Like before we are going to start with the configuration files for our .env.local and .env files in the server and client folders. We need to add the same secrets to the files. Find your application on the Pusher platform and then find the App keys.

The App keys must be added to the env files with the right variables. Take a note of this key difference. Our client .env.local env file must have NEXT_PUBLIC at the start, and the .env file in the server folder does not require it and you can see that in the examples below.

Here is our .env.local file which is in the client folder:

NEXT_PUBLIC_PUBNUB_PUBLISH_KEY=your-publish-key
NEXT_PUBLIC_PUBNUB_SUBSCRIBE_KEY=your-subscribe-key
NEXT_PUBLIC_PUSHER_APP_ID=your-app-id
NEXT_PUBLIC_PUSHER_APP_KEY=your-app-key
NEXT_PUBLIC_PUSHER_APP_SECRET=your-app-secret
NEXT_PUBLIC_PUSHER_APP_CLUSTER=your-cluster
로그인 후 복사

And this is the .env file which can be found in the server folder:

PUSHER_APP_ID=your-app-id
PUSHER_APP_KEY=your-app-key
PUSHER_APP_SECRET=your-app-secret
PUSHER_APP_CLUSTER=your-cluster
로그인 후 복사

Time to work on the frontend so you know the drill add this code to the components/ChatPusher.js file:

import { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import Pusher from 'pusher-js';
import ChatInterface from './ChatInterface';

export default function ChatPusher({ activeUser }) {
  const [chats, setChats] = useState([]);
  const [count, setCount] = useState(0);
  const bottomRef = useRef(null);

  let channel;
  let pusher;

  useEffect(() => {
    pusher = new Pusher(process.env.NEXT_PUBLIC_PUSHER_APP_KEY, {
      cluster: process.env.NEXT_PUBLIC_PUSHER_APP_CLUSTER,
      useTLS: true,
      channelAuthorization: {
        endpoint: 'http://localhost:8000/auth',
      },
    });

    channel = pusher.subscribe('presence-chatroom');
    channel.bind('new-message', ({ chat = null }) => {
      if (chat) {
        setChats((prevChats) => [...prevChats, chat]);
      }
    });

    channel.bind('pusher:subscription_succeeded', () => {
      updateMemberCount(channel);
    });

    channel.bind('pusher:member_added', () => {
      updateMemberCount(channel);
    });
    channel.bind('pusher:member_removed', () => {
      updateMemberCount(channel);
    });

    const scrollToBottom = () => {
      bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
    };

    scrollToBottom();

    return () => {
      pusher.disconnect();
    };
  }, [chats]);

  const updateMemberCount = (presenceChannel) => {
    const memberCount = Object.keys(presenceChannel.members.members).length;
    console.log('Count people online', memberCount);
    setCount(memberCount);
  };

  const handleKeyUp = (evt) => {
    const value = evt.target.value;
    if (evt.keyCode === 13 && !evt.shiftKey) {
      const chat = { user: activeUser, message: value, timestamp: +new Date() };
      evt.target.value = '';
      axios.post('http://localhost:8000/message', chat);
    }
  };

  return activeUser ? (
    <>
      <ChatInterface
        activeUser={activeUser}
        count={count}
        chats={chats}
        handleKeyUp={handleKeyUp}
        bottomRef={bottomRef}
      />
    </>
  ) : null;
}
로그인 후 복사

There are similarities here to our PubNub component which matches this. We can subscribe to the channels, publish different messages and handle the presence. Although all of this is now done via the backend which now also works with basic authentication. Unlike the PubNub version however this version can accurately see how many users are online as well as when users are active, join and leave the group chat.

An authentication route is present for authenticating users and we incorporated a message route for posting all messages to our server.

Our frontend is almost completed just one file remains so add this code to our pusher.page.js file now:

'use client';
import Header from '../components/Header';
import UserLogin from '../components/UserLogin';

export default function Pusher() {
  return (
    <div>
      <Header />
      <UserLogin bgColor={'bg-emerald-800 '} appName={'Pusher Chat'} />
    </div>
  );
}
로그인 후 복사

This file ensures that our Pusher version has a working route. All thats left is to get the messaging app up and running when we do the server file next.

Before we do that we should setup our run script in our package.json file so add this script to it:

"scripts": {
"start": "node index.js"
},
로그인 후 복사

Alright, last file! Add this code to our index.js file in the server folder so we can complete the backend:

const cors = require('cors');
const Pusher = require('pusher');
const express = require('express');
require('dotenv').config();
const crypto = require('crypto');
const dev = process.env.NODE_ENV !== 'production';
const port = process.env.PORT || 8000;

const pusher = new Pusher({
  appId: process.env.PUSHER_APP_ID,
  key: process.env.PUSHER_APP_KEY,
  secret: process.env.PUSHER_APP_SECRET,
  cluster: process.env.PUSHER_APP_CLUSTER,
  useTLS: true,
});

const server = express();
server.use(cors());
server.use(express.json());
server.use(express.urlencoded({ extended: false }));

const chatHistory = { messages: [] };

server.post('/message', (req, res) => {
  const { user = null, message = '', timestamp = +new Date() } = req.body;
  const chat = { user, message, timestamp };
  chatHistory.messages.push(chat);
  pusher.trigger('presence-chatroom', 'new-message', { chat });
  res.status(200).send('Message sent successfully.');
});
server.post('/messages', (req, res) => {
  res.json({ ...chatHistory, status: 'success' });
});

server.post('/auth', (req, res) => {
  const socketId = req.body.socket_id;
  const channel = req.body.channel_name;
  console.log('Socket and channel', socketId, channel);
  const userId = crypto.randomBytes(8).toString('hex');

  const presenceData = {
    user_id: userId,
    user_info: {
      name: 'Anonymous User',
    },
  };

  const auth = pusher.authorizeChannel(socketId, channel, presenceData);
  res.send(auth);
});

server.listen(port, (err) => {
  if (err) throw err;
  console.log(`Server is running on port: ${port} http://localhost:${port}`);
});
로그인 후 복사

Just a quick run through of this file so we can understand how it works. If you don't know its an Express server file which can connect to the Pusher API and it has routes for the authentication, message posting, in addition to getting chat history for all messages.

For connectivity, cors is implemented, so we don't get any of those annoying errors when trying to connect to different servers. The crypto module is used to doing various tasks like hash generation and encrypting and decrypting data.

With our codebase at MVP status, all you have to do is run the backend server in a different terminal window with the following command as shown below:

npm run start
로그인 후 복사

So our server will run on port 8000 and you can change this in the server code if need be. Of course our Next.js application runs on port 3000, they need to be on different ports for obvious reasons. You already know how to use the PubNub version, the Pusher version works much the same.

Congratulations you have reached the end of this tutorial and created a working real-time messaging application!

Conclusion

Thats it we have completed the tutorial, learned about both real-time messaging applications and built a working demo application. As you have learned both platforms offer a similar feature set although Pusher has self-hosted and cloud options whereas PubNub offers only the later.

Ultimately your choice of platform will come down to what you make of their pros and cons. They have a free plan, so testing them is pretty easy to do. Pusher has flexible pricing in contrast to PubNubs strict pricing that offers much cheaper starter options priced at $98 compared to $49 for the Pusher startup option.

위 내용은 React에서 실시간 메시징 앱을 만드는 PubNub 및 Pusher의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!