0Pricing
React Academy · درس

إنشاء مكوّن دردشة فورية

اعرض الرسائل المباشرة في قائمة دردشة قابلة للتمرير باستخدام أحداث WebSocket وحالة React.

إنشاء مكوّن دردشة فورية درس مجاني في React Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في React Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة React Academy 4 دروس في المجموع.

بنية مكوّن المحادثة

تتكوّن المحادثة الآنية من ثلاثة أجزاء: قائمة الرسائل (العرض)، وحقل إدخال الرسالة (الإرسال)، وطبقة اتصال WebSocket/Socket.IO. أبقوا منطق المقبس في خطاف مخصّص.

بنية بيانات الرسالة

عرّفوا واجهة TypeScript لرسائل المحادثة للحفاظ على أمان الأنواع في المكوّن بأكمله.

interface Message {
  id: string;
  text: string;
  sender: string;
  timestamp: number;
}

const [messages, setMessages] = useState<Message[]>([]);

خطاف useChat

غلّفوا الاتصال وحالة الرسائل ودالة الإرسال في خطاف واحد.

function useChat(roomId: string) {
  const [messages, setMessages] = useState<Message[]>([]);

  useEffect(() => {
    socket.connect();
    socket.emit('join-room', roomId);
    socket.on('message', (msg: Message) => setMessages(m => [...m, msg]));
    return () => {
      socket.off('message');
      socket.emit('leave-room', roomId);
      socket.disconnect();
    };
  }, [roomId]);

  const sendMessage = useCallback((text: string) => {
    const msg: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
    socket.emit('message', msg);
  }, []);

  return { messages, sendMessage };
}

مكوّن قائمة الرسائل

اعرضوا الرسائل في قائمة قابلة للتمرير. استخدموا useRef مع عنصر الإشارة الموجود في الأسفل، ومرّروا إليه عند وصول رسائل جديدة.

function MessageList({ messages }: { messages: Message[] }) {
  const bottomRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  return (
    <div className="message-list">
      {messages.map(msg => (
        <div key={msg.id} className={`msg ${msg.sender === 'me' ? 'mine' : 'theirs'}`}>
          <span>{msg.sender}</span>
          <p>{msg.text}</p>
        </div>
      ))}
      <div ref={bottomRef} />
    </div>
  );
}

مكوّن إدخال الرسالة

هو حقل إدخال متحكَّم فيه يُطلق الحدث عند الضغط على Enter أو النقر على الزر. أفرغوا الحقل بعد الإرسال.

function MessageInput({ onSend }: { onSend: (text: string) => void }) {
  const [text, setText] = useState('');

  const handleSend = () => {
    if (!text.trim()) return;
    onSend(text.trim());
    setText('');
  };

  return (
    <div className="input-row">
      <input
        value={text}
        onChange={e => setText(e.target.value)}
        onKeyDown={e => e.key === 'Enter' && handleSend()}
        placeholder="Type a message..."
      />
      <button onClick={handleSend}>Send</button>
    </div>
  );
}

تجميع واجهة المحادثة

ركّبوا الخطاف والمكوّنات الفرعية في مكوّن ChatRoom.

function ChatRoom({ roomId }: { roomId: string }) {
  const { messages, sendMessage } = useChat(roomId);

  return (
    <div className="chat-room">
      <h2>Room: {roomId}</h2>
      <MessageList messages={messages} />
      <MessageInput onSend={sendMessage} />
    </div>
  );
}

التحديثات التفاؤلية

أضيفوا الرسالة إلى الحالة المحلية فوراً قبل أن يؤكّدها الخادم، لتوفير استجابة فورية. وقوموا بمواءمتها أو إزالتها إذا أعاد الخادم خطأً.

const sendMessage = useCallback((text: string) => {
  const optimistic: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
  setMessages(m => [...m, optimistic]); // instant feedback
  socket.emit('message', optimistic, (err) => {
    if (err) setMessages(m => m.filter(msg => msg.id !== optimistic.id));
  });
}, []);

مؤشرات الكتابة

أطلقوا حدث typing عند تغيّر الإدخال (مع تأخير مضاد للتكرار)، واستمعوا إلى أحداث كتابة الآخرين لعرض مؤشر.

const emitTyping = useMemo(() => debounce(() => socket.emit('typing'), 300), []);

useEffect(() => {
  socket.on('user-typing', (user) => setTypingUser(user));
  return () => socket.off('user-typing');
}, []);

طوابع زمنية للرسائل

نسّقوا الطوابع الزمنية باستخدام Intl.DateTimeFormat لعرض يتوافق مع الإعدادات المحلية.

function formatTime(ts: number) {
  return new Intl.DateTimeFormat('en', { hour: '2-digit', minute: '2-digit' }).format(ts);
}

<span className="timestamp">{formatTime(msg.timestamp)}</span>

إيصالات القراءة

أطلقوا حدث read عندما يعرض المستخدم الرسائل، واستمعوا إلى تأكيدات القراءة من الخادم لعرض علامات الاختيار.

قائمة رسائل افتراضية

بالنسبة إلى سجلات المحادثات الطويلة، استخدموا react-window أو react-virtual لإجراء افتراضية لقائمة الرسائل وعرض الصفوف المرئية فقط.

تحديد سجل الرسائل

حدّدوا حجم مصفوفة الرسائل في الحالة لمنع نمو الذاكرة بلا حدود أثناء الجلسات الطويلة.

socket.on('message', (msg: Message) => {
  setMessages(prev => [...prev.slice(-499), msg]); // keep last 500
});

تحقّق سريع

ما الغرض من التمرير إلى عنصر الإشارة الموجود في أسفل قائمة المحادثة عند وصول رسائل جديدة؟

مراجعة

أنشئوا محادثة آنية باستخدام خطاف useChat الذي يغلّف منطق المقبس، وMessageList مع التمرير التلقائي، وMessageInput الذي يفرغ الحقل عند الإرسال. استخدموا التحديثات التفاؤلية لتوفير استجابة فورية، وحدّدوا سجل الرسائل لتجنّب تسرّبات الذاكرة.

الأسئلة الشائعة

هل درس «إنشاء مكوّن دردشة فورية» مجاني؟

نعم — نص درس «إنشاء مكوّن دردشة فورية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة React Academy، انتقل إلى CoddyKit PRO. تتضمن دورة React Academy 4 دروس في المجموع.

ماذا ستتعلم في «إنشاء مكوّن دردشة فورية»؟

اعرض الرسائل المباشرة في قائمة دردشة قابلة للتمرير باستخدام أحداث WebSocket وحالة React. تتمرن على React Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ React Academy؟

لا تُشترط خبرة سابقة. React Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «إنشاء مكوّن دردشة فورية»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس React Academy هذا؟

نعم. كل درس في React Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. أساسيات WebSocket في المتصفح
  2. استخدام Socket.IO مع React
  3. إنشاء مكوّن دردشة فورية
  4. إعادة الاتصال ومعالجة الأخطاء والتنظيف
← العودة إلى React Academy