You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于使用pusher-js与Next.js实现实时功能的入门教程及流程咨询

Hey there! I totally get where you're coming from—official docs can feel pretty dense when you're trying to wrap your head around real-time features for the first time. Let me walk you through a complete, beginner-friendly step-by-step flow to build real-time functionality with pusher-js and Next.js, using a simple chat app as an example.

Step 1: Set Up Your Pusher Account & Project
  • Head over to Pusher's dashboard and create a free account if you don't have one.
  • Create a new project (select "Chat" as the use case if you want pre-configured settings, but "Custom" works too).
  • Once your project is ready, note down these credentials from the "App Keys" tab: App ID, Key, Secret, and Cluster—you'll need these later.
Step 2: Initialize Your Next.js Project & Install Dependencies
  • Start by creating a new Next.js project if you don't have one:
    npx create-next-app@latest pusher-nextjs-demo
    cd pusher-nextjs-demo
    
  • Install the required packages:
    npm install pusher pusher-js
    
    (Use yarn add or pnpm add if you prefer those package managers)
Step 3: Configure Environment Variables
  • Create a .env.local file in the root of your project and add your Pusher credentials:
    # Server-side credentials (keep these private!)
    PUSHER_APP_ID=your-app-id-here
    PUSHER_SECRET=your-secret-here
    # Client-side credentials (prefixed with NEXT_PUBLIC_ so they're accessible in the browser)
    NEXT_PUBLIC_PUSHER_KEY=your-key-here
    NEXT_PUBLIC_PUSHER_CLUSTER=your-cluster-here
    
  • Restart your Next.js dev server to load these variables.
Step 4: Build the Backend (Next.js API Route)

We'll use Next.js API routes to send events to Pusher (this keeps your Pusher secret safe, since it runs server-side).

  • Create a new file based on your Next.js router setup:

For Pages Router (pages/api/send-message.js):

import Pusher from 'pusher';

// Initialize Pusher server client
const pusher = new Pusher({
  appId: process.env.PUSHER_APP_ID,
  key: process.env.PUSHER_KEY,
  secret: process.env.PUSHER_SECRET,
  cluster: process.env.PUSHER_CLUSTER,
  useTLS: true,
});

export default async function handler(req, res) {
  // Only allow POST requests
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    const { message, username } = req.body;
    // Trigger a "new-message" event on the "chat" channel
    await pusher.trigger('chat', 'new-message', {
      message,
      username,
    });
    res.status(200).json({ success: true });
  } catch (error) {
    res.status(500).json({ error: 'Failed to send message' });
  }
}

For App Router (app/api/send-message/route.js):

import Pusher from 'pusher';

const pusher = new Pusher({
  appId: process.env.PUSHER_APP_ID,
  key: process.env.PUSHER_KEY,
  secret: process.env.PUSHER_SECRET,
  cluster: process.env.PUSHER_CLUSTER,
  useTLS: true,
});

export async function POST(request) {
  try {
    const { message, username } = await request.json();
    await pusher.trigger('chat', 'new-message', { message, username });
    return Response.json({ success: true });
  } catch (error) {
    return Response.json({ error: 'Failed to send message' }, { status: 500 });
  }
}
Step 5: Build the Frontend (Real-Time UI)

Now let's create a page that subscribes to Pusher events and lets users send messages.

  • Open your main page file and replace its content with:

For Pages Router (pages/index.js):

import { useEffect, useState } from 'react';
import Pusher from 'pusher-js';

export default function Home() {
  const [messages, setMessages] = useState([]);
  const [inputMessage, setInputMessage] = useState('');
  const [username, setUsername] = useState('Guest');

  useEffect(() => {
    // Initialize Pusher client for the frontend
    const pusher = new Pusher(process.env.NEXT_PUBLIC_PUSHER_KEY, {
      cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER,
    });

    // Subscribe to the "chat" channel
    const chatChannel = pusher.subscribe('chat');

    // Listen for new messages
    chatChannel.bind('new-message', (data) => {
      setMessages(prevMessages => [...prevMessages, data]);
    });

    // Cleanup: Unsubscribe and disconnect when the component unmounts
    return () => {
      chatChannel.unbind_all();
      pusher.unsubscribe('chat');
      pusher.disconnect();
    };
  }, []);

  const handleSendMessage = async (e) => {
    e.preventDefault();
    if (!inputMessage.trim()) return;

    try {
      // Send message to our API route
      await fetch('/api/send-message', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message: inputMessage, username }),
      });
      setInputMessage('');
    } catch (error) {
      alert('Failed to send message. Please try again.');
    }
  };

  return (
    <div style={{ maxWidth: '600px', margin: '2rem auto', padding: '0 1rem' }}>
      <h1>Real-Time Chat Demo</h1>
      <input
        type="text"
        placeholder="Enter your username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        style={{ width: '100%', padding: '0.5rem', marginBottom: '1rem' }}
      />
      <div
        style={{
          border: '1px solid #e5e7eb',
          padding: '1rem',
          height: '350px',
          overflowY: 'auto',
          marginBottom: '1rem',
          borderRadius: '0.5rem',
        }}
      >
        {messages.length === 0 ? (
          <p style={{ color: '#6b7280' }}>No messages yet—send the first one!</p>
        ) : (
          messages.map((msg, index) => (
            <div key={index} style={{ marginBottom: '0.75rem' }}>
              <strong style={{ color: '#1f2937' }}>{msg.username}:</strong>
              <span style={{ marginLeft: '0.5rem' }}>{msg.message}</span>
            </div>
          ))
        )}
      </div>
      <form onSubmit={handleSendMessage} style={{ display: 'flex', gap: '0.5rem' }}>
        <input
          type="text"
          placeholder="Type a message..."
          value={inputMessage}
          onChange={(e) => setInputMessage(e.target.value)}
          style={{ flex: 1, padding: '0.5rem', borderRadius: '0.25rem', border: '1px solid #e5e7eb' }}
        />
        <button
          type="submit"
          style={{
            padding: '0.5rem 1rem',
            backgroundColor: '#3b82f6',
            color: 'white',
            border: 'none',
            borderRadius: '0.25rem',
            cursor: 'pointer',
          }}
        >
          Send
        </button>
      </form>
    </div>
  );
}

For App Router (app/page.js):

'use client'; // Mark this as a client component since we're using useState/useEffect

import { useEffect, useState } from 'react';
import Pusher from 'pusher-js';

export default function Home() {
  const [messages, setMessages] = useState([]);
  const [inputMessage, setInputMessage] = useState('');
  const [username, setUsername] = useState('Guest');

  useEffect(() => {
    const pusher = new Pusher(process.env.NEXT_PUBLIC_PUSHER_KEY, {
      cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER,
    });

    const chatChannel = pusher.subscribe('chat');
    chatChannel.bind('new-message', (data) => {
      setMessages(prev => [...prev, data]);
    });

    return () => {
      chatChannel.unbind_all();
      pusher.unsubscribe('chat');
      pusher.disconnect();
    };
  }, []);

  const handleSendMessage = async (e) => {
    e.preventDefault();
    if (!inputMessage.trim()) return;

    try {
      await fetch('/api/send-message', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message: inputMessage, username }),
      });
      setInputMessage('');
    } catch (error) {
      alert('Failed to send message. Please try again.');
    }
  };

  return (
    <div style={{ maxWidth: '600px', margin: '2rem auto', padding: '0 1rem' }}>
      <h1>Real-Time Chat Demo</h1>
      <input
        type="text"
        placeholder="Enter your username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        style={{ width: '100%', padding: '0.5rem', marginBottom: '1rem' }}
      />
      <div
        style={{
          border: '1px solid #e5e7eb',
          padding: '1rem',
          height: '350px',
          overflowY: 'auto',
          marginBottom: '1rem',
          borderRadius: '0.5rem',
        }}
      >
        {messages.length === 0 ? (
          <p style={{ color: '#6b7280' }}>No messages yet—send the first one!</p>
        ) : (
          messages.map((msg, index) => (
            <div key={index} style={{ marginBottom: '0.75rem' }}>
              <strong style={{ color: '#1f2937' }}>{msg.username}:</strong>
              <span style={{ marginLeft: '0.5rem' }}>{msg.message}</span>
            </div>
          ))
        )}
      </div>
      <form onSubmit={handleSendMessage} style={{ display: 'flex', gap: '0.5rem' }}>
        <input
          type="text"
          placeholder="Type a message..."
          value={inputMessage}
          onChange={(e) => setInputMessage(e.target.value)}
          style={{ flex: 1, padding: '0.5rem', borderRadius: '0.25rem', border: '1px solid #e5e7eb' }}
        />
        <button
          type="submit"
          style={{
            padding: '0.5rem 1rem',
            backgroundColor: '#3b82f6',
            color: 'white',
            border: 'none',
            borderRadius: '0.25rem',
            cursor: 'pointer',
          }}
        >
          Send
        </button>
      </form>
    </div>
  );
}
Step 6: Test the Real-Time Functionality
  • Start your Next.js dev server: npm run dev
  • Open two browser windows (or tabs) pointing to http://localhost:3000
  • Enter different usernames in each tab, send messages, and watch them appear in real-time across both tabs!

Pro Tips to Level Up Your Implementation

  • Private Channels: For authenticated users, use Pusher's private channels to restrict access. You'll need to create an auth API route that verifies the user's session before granting channel access.
  • Error Handling: Add more robust error handling (like displaying error messages in the UI instead of alerts) and handle Pusher disconnections/reconnections gracefully.
  • Reusable Pusher Client: Create a utility file (e.g., utils/pusher.js) to initialize the Pusher client once, so you don't repeat code in every component.
  • Rate Limiting: Add rate limiting to your API routes to prevent abuse (packages like express-rate-limit work with Next.js API routes).

内容的提问来源于stack exchange,提问作者Abdelrhman Gad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 19:32:30