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

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

실시간 데이터는 요즘 최신 애플리케이션의 핵심 요소 중 하나입니다. 양방향 정보를 보낼 수 있는 시스템을 갖추면 다양한 정보를 최신 상태로 유지할 수 있습니다. 이러한 예로는 메시징 애플리케이션, 재무 데이터에 사용되는 대시보드용 데이터 분석, 증강 및 가상 애플리케이션에 사용되는 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

푸셔 버전에는 녹색 머리글이 있으며 이를 통해 두 머리글의 차이점을 시각적으로 알 수 있습니다.
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에 계정이 있는지 확인하세요. 이제 두 플랫폼 모두에서 계정을 만드는 과정을 신속하게 진행할 것이므로 아직 계정을 만들지 않았다면 계속 진행하세요.

PubNub에서 계정 만들기

PubNub을 시작으로 해당 홈페이지에 접속 후 오른쪽 상단의 버튼을 클릭하시면 아래와 같이 무료로 사용해 보실 수 있습니다.

PubNub vs Pusher creating a realtime messaging app in React

이제 등록 페이지가 표시되므로 양식을 사용하여 계정을 만드세요.

PubNub vs Pusher creating a realtime messaging app in React

이제 계정이 생성되었으므로 대시보드에 액세스할 수 있습니다. 메뉴를 사용하여 키 세트 섹션으로 이동한 다음 앱과 해당 키 세트를 찾으세요. 앱이 아직 없다면 만들어야 하는 부분이기도 합니다.

이제 API 키가 표시되므로 사용자와 데이터를 추적하는 데 필요하므로 현재 상태 및 지속성 옵션이 켜져 있는지 확인하세요.

PubNub vs Pusher creating a realtime messaging app in React

Pusher에서 계정 만들기

맞습니다. 이제 PubNub 계정 작업이 완료되었습니다. 이제 Pusher 계정을 작업해 보겠습니다. 이전과 마찬가지로 홈페이지에 접속하여 페이지 오른쪽 상단에 있는 회원가입 버튼을 클릭하세요.

PubNub vs Pusher creating a realtime messaging app in React

이제 다음 화면에서 양식을 사용하여 여기에 표시된 것과 같은 계정을 만드세요.

PubNub vs Pusher creating a realtime messaging app in React

채널을 생성해야 하므로 대시보드 페이지에서 관리 버튼을 선택하세요.

PubNub vs Pusher creating a realtime messaging app in React
채널 화면이 될 다음 페이지에서 이 스크린샷과 같이 앱 만들기 버튼을 사용하여 앱을 만듭니다.

PubNub vs Pusher creating a realtime messaging app in React

이제 양식으로 이동할 수 있으며 이 예에서 볼 수 있듯이 구성은 사용 사례에 맞게 맞춤화되어야 합니다.

PubNub vs Pusher creating a realtime messaging app in React

따라서 해당 단계가 완료되면 채널 페이지가 여기처럼 표시되어야 합니다.
PubNub vs Pusher creating a realtime messaging app in React
사이드바 메뉴에 있는 앱 키를 클릭하면 나중에 필요한 API 키에 액세스할 수 있습니다.

PubNub vs Pusher creating a realtime messaging app in React

이제 계정 설정 단계가 완료되었습니다. 다음 섹션에서는 앱 코드를 시작하겠습니다. 첫 번째 단계는 폴더 등을 사용하여 프로젝트 아키텍처를 만드는 것입니다. 모든 명령을 수동으로 작성할 필요가 없도록 명령줄에 대한 복사 및 붙여넣기 스크립트를 만들었습니다. 컴퓨터에서 realtime-chat-app이라는 프로젝트를 생성한 후 명령줄을 사용하여 해당 위치로 이동하세요.

React 애플리케이션 설정

Next.js를 사용하여 프로젝트를 생성한 후 쉘 스크립트를 사용하여 프로젝트를 설정합니다.

다음 명령을 실행하여 Next.js 프로젝트를 생성하는 것으로 시작합니다.

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

이제 구성 화면에서 Tailwind CSS와 앱 라우터를 선택하는 것이 중요합니다. 왜냐하면 이 프로젝트에는 해당 옵션이 필요하기 때문입니다.

여기 파일과 폴더를 생성하고 종속성을 설치하기 위한 셸 스크립트가 있습니다. 동일한 폴더 내에서 실행하면 클라이언트 폴더에 자동으로 CD가 설치됩니다. 이미 클라이언트 폴더에 있는 경우 스크립트의 첫 번째 줄을 생략할 수 있습니다.

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 ..
로그인 후 복사

여기서 많은 일이 일어나고 있으므로 이 스크립트가 무엇을 하는지 살펴보겠습니다.

  • 패키지와 PubNub 및 Pusher 패키지를 포함하는 프로젝트에 대한 종속성 설치
  • API 키용 환경 변수 파일 생성
  • 전체 앱의 파일, 폴더 및 구성 요소 만들기
  • Pusher가 API 액세스에 필요한 백엔드 서버 설정
  • 라우팅 및 로직 목적을 위한 서버 파일 구축

이 화면을 보세요. IDE에서 우리 프로젝트가 어떻게 보일지 살펴보세요.

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 학습자의 빠른 성장을 도와주세요!