chatstorm-client
v2.2.6
Published
A real-time chat client built using Socket.IO for seamless communication. Compatible with both React and React Native. This client handles connection, message exchange, event-driven updates, and user session management in a modular and extensible structur
Maintainers
Keywords
Readme
ChatStorm Client
A powerful React hook for real-time chat functionality using Socket.IO. ChatStorm Client provides an easy-to-use interface for integrating socket-based messaging into your React and React Native applications with comprehensive event handling and callback systems.
🚀 Features
- Real-time Communication: Instant message delivery and updates
- Socket.IO Integration: Robust WebSocket connection management
- Event-driven Architecture: Comprehensive callback system for all events
- Typing Indicators: Real-time typing status notifications
- Message History: Retrieve and search past conversations
- Chat Management: Join chats, get chat lists, and manage conversations
- Message Operations: Send, delete, and update messages (supports text, links, and media)
- Online Status: Check if users are online in real-time
- Error Handling: Built-in error notification system
- TypeScript Support: Full TypeScript definitions included
- Auto-reconnection: Automatic connection handling and cleanup
📦 Installation
Install the package via npm:
npm install chatstorm-clientPeer Dependencies
Make sure you have the following dependencies installed:
For React:
npm install react react-dom socket.io-clientFor React Native:
npm install react socket.io-client
# react-dom is not needed for React Native🏃♂️ Quick Start
React Native Setup
For React Native projects, you may need to install additional polyfills for Socket.IO:
npm install react-native-get-random-valuesThen import it at the top of your entry file (usually index.js or App.js):
import 'react-native-get-random-values';Basic Setup
import React from 'react';
import useChatSocket from 'chatstorm-client';
const ChatComponent = () => {
const BACKEND_SOCKET_URL = 'ws://localhost:3001';
const MONGO_USER_ID = 'your-user-id-here';
const {
messages,
sendMessage,
joinChat,
getChatList,
retrieveMessages,
updateTypingAlert,
deleteMessage,
leaveChat,
checkOnlineStatus,
disconnectUser,
setHandshakeSuccessCallback,
setMessageReceivedCallback,
setChatListCallback,
setRetrieveMessagesCallback,
setMessageSentCallback,
setMessageUpdateCallback,
setReceiverMessageUpdateCallback,
setTypingAlertCallback,
setOnLeaveCallback,
setChatStatusCallback,
setOnCheckOnlineStatus,
setOnErrorNotify,
setOnDisconnect,
socketInstance,
} = useChatSocket(BACKEND_SOCKET_URL, MONGO_USER_ID);
// Set up event callbacks
React.useEffect(() => {
setHandshakeSuccessCallback((data) => {
console.log('Connected successfully:', data);
});
setMessageReceivedCallback((message) => {
console.log('New message received:', message);
});
setChatListCallback((chatList) => {
console.log('Chat list updated:', chatList);
});
setRetrieveMessagesCallback((messages) => {
console.log('Messages retrieved:', messages);
});
setOnCheckOnlineStatus((data) => {
console.log('Online status:', data);
});
setOnErrorNotify((error) => {
console.error('Error notification:', error);
});
setOnDisconnect((data) => {
console.log('Disconnected:', data);
});
setChatStatusCallback((data) => {
if (data.isJoined) {
console.log('User joined chat:', data.data);
} else if (data.isLeft) {
console.log('User left chat');
}
});
}, []);
return (
<div>
<h1>Chat Application</h1>
{/* Your chat UI components here */}
</div>
);
};📚 API Reference
Hook Parameters
useChatSocket(serverUrl: string, userId: string)serverUrl: WebSocket server URL (e.g., 'ws://localhost:3001')userId: Unique identifier for the current user
Returned Functions
Core Functions
| Function | Parameters | Description |
|----------|------------|-------------|
| sendMessage | { receiverId: string, message: { text: string, link: string, media: string } } | Send a message to a specific user (supports text, link, and media) |
| joinChat | { receiverId: string } | Join a chat with another user |
| getChatList | { keyword?: string } | Retrieve list of available chats (keyword is optional) |
| retrieveMessages | { receiverId: string, keyword?: string } | Get message history with a user (keyword is optional, automatically marks messages as seen) |
| updateTypingAlert | { receiverId: string, isTyping: boolean } | Send typing status |
| deleteMessage | { messageId: string } | Delete a specific message |
| leaveChat | { receiverId: string } | Leave a chat conversation |
| checkOnlineStatus | { receiverId: string } | Check if a user is online |
| disconnectUser | () | Manually disconnect the user from the socket |
Callback Setters
| Function | Description |
|----------|-------------|
| setHandshakeSuccessCallback | Called when connection is established |
| setMessageReceivedCallback | Called when a new message is received |
| setMessageSentCallback | Called when a message is sent successfully |
| setChatListCallback | Called when chat list is updated |
| setRetrieveMessagesCallback | Called when messages are retrieved |
| setMessageUpdateCallback | Called when a message is updated |
| setReceiverMessageUpdateCallback | Called when receiver updates a message |
| setTypingAlertCallback | Called when typing status is received |
| setOnLeaveCallback | Called when a user leaves the chat |
| setChatStatusCallback | Called when chat status changes (user joined/left) |
| setOnCheckOnlineStatus | Called when online status is received |
| setOnErrorNotify | Called when an error notification is received |
| setOnDisconnect | Called when the socket connection is disconnected |
State
messages: Array of current messages in the chat
💡 Use Cases
1. Private Messaging App
import React, { useState } from 'react';
import useChatSocket from 'chatstorm-client';
const PrivateChat = () => {
const [currentChat, setCurrentChat] = useState(null);
const [messageInput, setMessageInput] = useState('');
const [chatList, setChatList] = useState([]);
const {
messages,
sendMessage,
joinChat,
getChatList,
retrieveMessages,
setMessageReceivedCallback,
setChatListCallback,
setRetrieveMessagesCallback,
} = useChatSocket('ws://localhost:3001', 'user123');
React.useEffect(() => {
// Load chat list on component mount
getChatList({ keyword: '' });
setChatListCallback((data) => {
setChatList(data.chats || []);
});
setMessageReceivedCallback((message) => {
console.log('New message:', message);
});
setRetrieveMessagesCallback((data) => {
console.log('Messages loaded:', data);
});
}, []);
const handleSendMessage = () => {
if (messageInput.trim() && currentChat) {
sendMessage({
receiverId: currentChat.id,
message: {
text: messageInput,
link: '',
media: '',
},
});
setMessageInput('');
}
};
const handleSelectChat = (chat) => {
setCurrentChat(chat);
joinChat({ receiverId: chat.id });
retrieveMessages({ receiverId: chat.id, keyword: '' });
};
return (
<div style={{ display: 'flex', height: '100vh' }}>
{/* Chat List Sidebar */}
<div style={{ width: '300px', borderRight: '1px solid #ccc' }}>
<h3>Chats</h3>
{chatList.map((chat) => (
<div
key={chat.id}
onClick={() => handleSelectChat(chat)}
style={{
padding: '10px',
cursor: 'pointer',
backgroundColor: currentChat?.id === chat.id ? '#f0f0f0' : 'white',
}}
>
{chat.name}
</div>
))}
</div>
{/* Chat Area */}
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
{currentChat ? (
<>
<div style={{ padding: '10px', borderBottom: '1px solid #ccc' }}>
<h3>{currentChat.name}</h3>
</div>
{/* Messages */}
<div style={{ flex: 1, padding: '10px', overflowY: 'auto' }}>
{messages.map((message, index) => (
<div key={index} style={{ marginBottom: '10px' }}>
<strong>{message.sender}:</strong> {message.content}
</div>
))}
</div>
{/* Message Input */}
<div style={{ padding: '10px', borderTop: '1px solid #ccc' }}>
<input
type="text"
value={messageInput}
onChange={(e) => setMessageInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
placeholder="Type a message..."
style={{ width: '100%', padding: '8px' }}
/>
<button onClick={handleSendMessage}>Send</button>
</div>
</>
) : (
<div style={{ padding: '20px', textAlign: 'center' }}>
Select a chat to start messaging
</div>
)}
</div>
</div>
);
};2. Customer Support Chat
import React, { useState, useEffect } from 'react';
import useChatSocket from 'chatstorm-client';
const CustomerSupport = () => {
const [isTyping, setIsTyping] = useState(false);
const [supportAgent, setSupportAgent] = useState(null);
const {
messages,
sendMessage,
joinChat,
updateTypingAlert,
setMessageReceivedCallback,
setHandshakeSuccessCallback,
setTypingAlertCallback,
} = useChatSocket('ws://support.example.com', 'customer123');
useEffect(() => {
// Connect to support agent
joinChat({ receiverId: 'support-agent-001' });
setHandshakeSuccessCallback((data) => {
console.log('Connected to support:', data);
setSupportAgent(data.agent);
});
setMessageReceivedCallback((message) => {
console.log('Support message:', message);
});
setTypingAlertCallback((data) => {
setIsTyping(data.isTyping);
});
}, []);
const handleTyping = (isTyping) => {
updateTypingAlert({
receiverId: 'support-agent-001',
isTyping,
});
};
return (
<div>
<h2>Customer Support</h2>
{supportAgent && (
<p>Connected to: {supportAgent.name}</p>
)}
<div>
{messages.map((message, index) => (
<div key={index}>
<strong>{message.sender}:</strong> {message.content}
</div>
))}
</div>
{isTyping && (
<p>Support agent is typing...</p>
)}
<input
type="text"
onFocus={() => handleTyping(true)}
onBlur={() => handleTyping(false)}
onKeyPress={(e) => {
if (e.key === 'Enter') {
sendMessage({
receiverId: 'support-agent-001',
message: {
text: e.target.value,
link: '',
media: '',
},
});
e.target.value = '';
}
}}
placeholder="Type your message..."
/>
</div>
);
};3. Group Chat Application
import React, { useState } from 'react';
import useChatSocket from 'chatstorm-client';
const GroupChat = () => {
const [groupMembers, setGroupMembers] = useState([]);
const [messageInput, setMessageInput] = useState('');
const {
messages,
sendMessage,
joinChat,
getChatList,
setMessageReceivedCallback,
setChatListCallback,
} = useChatSocket('ws://localhost:3001', 'user123');
React.useEffect(() => {
// Get group chats
getChatList({ keyword: 'group' });
setChatListCallback((data) => {
setGroupMembers(data.chats || []);
});
setMessageReceivedCallback((message) => {
console.log('Group message:', message);
});
}, []);
const handleSendGroupMessage = () => {
if (messageInput.trim()) {
// Send to all group members
groupMembers.forEach(member => {
sendMessage({
receiverId: member.id,
message: {
text: messageInput,
link: '',
media: '',
},
});
});
setMessageInput('');
}
};
return (
<div>
<h2>Group Chat</h2>
<div>
<h3>Members ({groupMembers.length})</h3>
{groupMembers.map(member => (
<span key={member.id}>{member.name}, </span>
))}
</div>
<div>
{messages.map((message, index) => (
<div key={index}>
<strong>{message.sender}:</strong> {message.content}
</div>
))}
</div>
<input
type="text"
value={messageInput}
onChange={(e) => setMessageInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSendGroupMessage()}
placeholder="Type a group message..."
/>
<button onClick={handleSendGroupMessage}>Send</button>
</div>
);
};📱 React Native Example
Here's a complete example for React Native:
import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, TouchableOpacity, FlatList, StyleSheet } from 'react-native';
import useChatSocket from 'chatstorm-client';
const ChatScreen = () => {
const [messageInput, setMessageInput] = useState('');
const [chatMessages, setChatMessages] = useState([]);
const BACKEND_SOCKET_URL = 'ws://your-server.com';
const USER_ID = 'your-user-id';
const {
messages,
sendMessage,
joinChat,
setMessageReceivedCallback,
setHandshakeSuccessCallback,
} = useChatSocket(BACKEND_SOCKET_URL, USER_ID);
useEffect(() => {
setHandshakeSuccessCallback((data) => {
console.log('Connected:', data);
// Join a chat after connection
joinChat({ receiverId: 'target-user-id' });
});
setMessageReceivedCallback((message) => {
setChatMessages((prev) => [...prev, message]);
});
}, []);
const handleSend = () => {
if (messageInput.trim()) {
sendMessage({
receiverId: 'target-user-id',
message: {
text: messageInput,
link: '',
media: '',
},
});
setMessageInput('');
}
};
return (
<View style={styles.container}>
<FlatList
data={chatMessages}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View style={styles.messageContainer}>
<Text style={styles.messageText}>{item.message}</Text>
</View>
)}
/>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
value={messageInput}
onChangeText={setMessageInput}
placeholder="Type a message..."
/>
<TouchableOpacity onPress={handleSend} style={styles.button}>
<Text style={styles.buttonText}>Send</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 10,
},
messageContainer: {
padding: 10,
marginVertical: 5,
backgroundColor: '#f0f0f0',
borderRadius: 5,
},
messageText: {
fontSize: 16,
},
inputContainer: {
flexDirection: 'row',
padding: 10,
},
input: {
flex: 1,
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 5,
padding: 10,
marginRight: 10,
},
button: {
backgroundColor: '#007bff',
padding: 10,
borderRadius: 5,
justifyContent: 'center',
},
buttonText: {
color: 'white',
fontWeight: 'bold',
},
});
export default ChatScreen;🔧 Advanced Configuration
Custom Event Handling
const AdvancedChat = () => {
const {
setMessageUpdateCallback,
setReceiverMessageUpdateCallback,
setOnLeaveCallback,
setOnCheckOnlineStatus,
setOnErrorNotify,
setOnDisconnect,
deleteMessage,
checkOnlineStatus,
disconnectUser,
} = useChatSocket('ws://localhost:3001', 'user123');
React.useEffect(() => {
// Handle message updates
setMessageUpdateCallback((data) => {
console.log('Message updated:', data);
// Update UI to show edited message
});
setReceiverMessageUpdateCallback((data) => {
console.log('Receiver updated message:', data);
// Handle when other user edits their message
});
setOnLeaveCallback((data) => {
console.log('User left:', data);
// Handle user leaving the chat
});
setOnCheckOnlineStatus((data) => {
console.log('User online status:', data);
// Handle online status updates
});
setOnErrorNotify((error) => {
console.error('Error occurred:', error);
// Handle error notifications
});
setOnDisconnect((data) => {
console.log('Socket disconnected:', data);
// Handle disconnection (e.g., show reconnection UI)
});
}, []);
const handleDeleteMessage = (messageId) => {
deleteMessage({ messageId });
};
const handleCheckOnline = (receiverId) => {
checkOnlineStatus({ receiverId });
};
const handleDisconnect = () => {
disconnectUser();
};
return (
<div>
{/* Your chat UI with delete functionality */}
</div>
);
};🐛 Troubleshooting
Common Issues
- Connection Failed
// Ensure your server URL is correct and accessible const serverUrl = 'ws://localhost:3001'; // or 'wss://' for secure connections
React Native Specific Issues
Socket.IO Connection Issues in React Native
- Make sure you've installed
react-native-get-random-valuesand imported it at the top of your entry file - For Android, ensure you have internet permissions in
AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" /> - For iOS, ensure your server URL uses
http://orhttps://instead ofws://orwss://in some cases - The package automatically configures transports for React Native compatibility
- Make sure you've installed
Metro Bundler Issues
- If you encounter module resolution errors, try clearing the Metro cache:
npx react-native start --reset-cache
- If you encounter module resolution errors, try clearing the Metro cache:
Network Requests Blocked
- For Android 9+, you may need to configure network security:
- Add
android:usesCleartextTraffic="true"toAndroidManifest.xmlfor HTTP connections - Or use HTTPS/WSS for production
- Add
- For Android 9+, you may need to configure network security:
Messages Not Received
// Make sure to set up callbacks before sending messages useEffect(() => { setMessageReceivedCallback((message) => { console.log('Message received:', message); }); }, []);Typing Indicators Not Working
// Ensure you're calling updateTypingAlert with correct parameters updateTypingAlert({ receiverId: 'target-user-id', isTyping: true, // or false });
Debug Mode
Enable debug logging by checking the browser console for socket events:
useEffect(() => {
setHandshakeSuccessCallback((data) => {
console.log('🔗 Connection established:', data);
});
setMessageReceivedCallback((message) => {
console.log('📨 Message received:', message);
});
setChatListCallback((chatList) => {
console.log('💬 Chat list updated:', chatList);
});
setOnCheckOnlineStatus((data) => {
console.log('🟢 Online status:', data);
});
setOnErrorNotify((error) => {
console.error('❌ Error notification:', error);
});
setOnDisconnect((data) => {
console.log('🔌 Disconnected:', data);
});
}, []);Chat Status Example
Handle chat join/leave notifications:
const ChatWithStatus = () => {
const { joinChat, leaveChat, setChatStatusCallback } = useChatSocket('ws://localhost:3001', 'user123');
useEffect(() => {
setChatStatusCallback((data) => {
if (data.isJoined) {
console.log('User joined:', data.data);
// Show notification: "User has joined the chat"
} else if (data.isLeft) {
console.log('User left the chat');
// Show notification: "User has left the chat"
}
});
}, []);
const handleJoinChat = (receiverId) => {
joinChat({ receiverId });
};
const handleLeaveChat = (receiverId) => {
leaveChat({ receiverId });
};
return (
<div>
<button onClick={() => handleJoinChat('target-user-id')}>Join Chat</button>
<button onClick={() => handleLeaveChat('target-user-id')}>Leave Chat</button>
</div>
);
};Online Status Example
Check if a user is online:
const ChatWithOnlineStatus = () => {
const [isOnline, setIsOnline] = useState(false);
const { checkOnlineStatus, setOnCheckOnlineStatus } = useChatSocket('ws://localhost:3001', 'user123');
useEffect(() => {
setOnCheckOnlineStatus((data) => {
setIsOnline(data.isOnline || false);
});
}, []);
const handleCheckStatus = (receiverId) => {
checkOnlineStatus({ receiverId });
};
return (
<div>
<button onClick={() => handleCheckStatus('target-user-id')}>
Check Online Status
</button>
{isOnline ? <span>🟢 Online</span> : <span>🔴 Offline</span>}
</div>
);
};Disconnect Example
Manually disconnect from the socket:
const ChatWithDisconnect = () => {
const { disconnectUser, setOnDisconnect } = useChatSocket('ws://localhost:3001', 'user123');
useEffect(() => {
setOnDisconnect((data) => {
console.log('Disconnected from server:', data);
// Handle disconnection (e.g., show offline message, clear UI)
});
}, []);
const handleLogout = () => {
// Disconnect before logging out
disconnectUser();
// Additional logout logic here
};
return (
<div>
<button onClick={handleLogout}>Logout</button>
</div>
);
};📄 License
ISC License - see package.json for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📞 Support
For support and questions, please open an issue on the GitHub repository.
🔽 Download Examples (ZIP)
React Web Example ZIP
👉 https://github.com/Vikas-Rajput-JS/Chatstorm-client/raw/refs/heads/master/test/react-web.zipReact Native Example ZIP
👉 https://github.com/Vikas-Rajput-JS/Chatstorm-client/raw/refs/heads/master/test/native.zip
Made with ❤️ by Vikas Rajput
