{"id":20578624,"url":"https://github.com/chatscope/use-chat","last_synced_at":"2025-04-06T01:08:58.959Z","repository":{"id":43741106,"uuid":"365237024","full_name":"chatscope/use-chat","owner":"chatscope","description":"React hook for state management in chat applications.","archived":false,"fork":false,"pushed_at":"2023-11-06T13:31:15.000Z","size":137776,"stargazers_count":151,"open_issues_count":10,"forks_count":24,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-29T23:11:09.904Z","etag":null,"topics":["chat","comments","communication","frontend","headless","instant-messaging","library","messenger","react","reusable","social","ui"],"latest_commit_sha":null,"homepage":"https://chatscope.io","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chatscope.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-07T13:09:14.000Z","updated_at":"2025-03-24T03:02:42.000Z","dependencies_parsed_at":"2024-06-18T17:12:46.367Z","dependency_job_id":null,"html_url":"https://github.com/chatscope/use-chat","commit_stats":{"total_commits":99,"total_committers":2,"mean_commits":49.5,"dds":"0.010101010101010055","last_synced_commit":"43a239c973119acece801fe1d523115328521744"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatscope%2Fuse-chat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatscope%2Fuse-chat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatscope%2Fuse-chat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chatscope%2Fuse-chat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chatscope","download_url":"https://codeload.github.com/chatscope/use-chat/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247419860,"owners_count":20936012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chat","comments","communication","frontend","headless","instant-messaging","library","messenger","react","reusable","social","ui"],"created_at":"2024-11-16T06:13:59.208Z","updated_at":"2025-04-06T01:08:58.939Z","avatar_url":"https://github.com/chatscope.png","language":"TypeScript","funding_links":[],"categories":["State management"],"sub_categories":[],"readme":"# Use Chat\n\n[![Actions Status](https://github.com/chatscope/chat-ui-kit-react/workflows/build/badge.svg)](https://github.com/chatscope/use-chat/actions) [![npm version](https://img.shields.io/npm/v/@chatscope/use-chat.svg?style=flat)](https://npmjs.com/@chatscope/use-chat) [![](https://img.shields.io/npm/l/@chatscope/use-chat?dummy=unused)](https://github.com/chatscope/use-chat/blob/main/LICENSE) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n!!! Please do not use version 1.5.0 it has wrong property names !!!\n\nReact hook for state management in chat applications.\n\nFull documentation is not available yet, but **will be prepared**.\n\nIf you are interested in this library and need more documentation,\nplease let me know by adding one of the positive reactions (+1, Heart, Rocket) in the dedicated issue here:  [https://github.com/chatscope/use-chat/issues/1](https://github.com/chatscope/use-chat/issues/1)\n\n## What is it?\n\nThis is a headless chat library. Think of it as something like a Formik but for chat apps.\n\nThe library can be used both with [@chatscope/chat-ui-kit-react](https://github.com/chatscope/chat-ui-kit-react) as well as with other chat components. \n\nThe goal of it is to provide a tool for handling features that are most often implemented in chat applications.  \nPrimarily it's an application state management as well as some nice addons such as debounce or throttling of sending or receiving typing indicator signaling.\n\n## Why?\n\nThe logic of chat applications is often repetitive. Most of these applications contains a user list, a conference list and of course messages.\nThere are at least a few chat API providers on the market. They provide saas services that you can use to build a chat application.\nYou also almost always get a ready-to-use, simple messaging library from them. Such a library encapsulates a complex communication protocol.  \nSometimes you also get UI components and hooks/providers that bind the UI to the provider's messaging library.\nBoth are closely related, which makes replacing the messaging library or UI components a lot of work. \n\nIn this case you have to take care of how to keep in your app: a list of contacts and theirs statuses, a list of messages for each contact, switching between chats, setting an active chat, rendering messages and so on...   \n\nIf you create your own backed and implement the communication layer yourself, you will also not avoid doing all these things.\n\nIsn't it better to focus on the business functionality of the application? On the layout, colour selection etc., instead of wondering how to find a message in the array to set its state to \"read\"?\n\nSuch things often turn out to be more complicated to do than they seem.\n\nFor example, a message list is not always a flat array.\nIt will often be an object with messages assigned to users and conversations, and additionally, it will be grouped into blocks of incoming and outgoing messages. \n\nAdding a message to the list requires roughly the following steps:\n- find a message list for a given conversation,\n- find the last group,\n- check if this is the group of the user the message comes from,\n- if it's not, then create a group and add the message to it\n- add the group to the list\n\nUff, there is a bit of it, right?\n\nSuch things should be closed in separate logic libraries, which can be used in a simple and intuitive way.\nThe implementation of a consistent interface also provides the possibility of internal tuning (e.g. changing the data structure) without changing the way the library is used.\n\n## Features\n\n- handling users states (with user business properties such as name, avatar, presence etc.)\n- handling conversations state (including current conversation)\n- handling grouped messages state for many conversations\n- sending debounced typing indicator\n- auto throttling received typing indicator\n- handling current message input value\n- handling message drafts\n- updating existed messages\n- support for any communication service\n\n## Installation\n\nUsing yarn.\n\n```sh\nyarn add @chatscope/use-chat\n```\n\nUsing npm.\n\n```sh\nnpm install @chatscope/use-chat\n```\n\n## Architecture\n\nThe library consist of three parts:\n\n- storage - the place where the state is kept\n- ChatProvider - chat context provider\n- useChat - hook that binds storage service and UI\n\n### BasicStorage\n\nThis is a class that implements the IStorage interface. \nAll data such as conversations, messages, current conversation indicator etc sits in the storage. \nBasicStorage is the basic implementation of the IStorage. It should be fully functional, and can be used for most applications.\nHowever, it is possible to write new implementations e.g. based on redux or another state library.\nThat is why the storage is provided to ChatProvider from the outside. \n\n### ExampleChatService\n\nThis is a class that implements IChatService interface.\nThe purpose of this service is to maintain a connection with the chat server, send and receive messages and chat protocol commands.\nThis is a point that connects your chat server with the library.\nTo use this library, you need to write your own ChatService that implements the IChatService interface.\nThe implementation of the service depends on which chat server you are using.\nThe content of the service can be your code written from scratch, but the service also can be an encapsulation layer for any ready to use chat communication library   \nThere is [src/examples/ExampleChatService.ts](https://github.com/chatscope/use-chat/blob/main/src/examples/ExampleChatService.ts) available for a quick start. This is a good starting point for developing the real service for your application.\n\nAt the future I will provide more examples showing real communication with socket.io based chat server.  \n\nService implementations for some SAAS providers will also be available. \n\n### Service factory\n\nIt is a simple function that you need to implement yourself.\nThis function receives a chat storage object (IChatStorage) as the first argument and update function as the second.\nThis function must return an instance of the class implementing IChatService.\nSometimes in your ChatService implementation, you will need to get values from the storage as well as save them to the storage.\nHere you can pass the storage to your service. Access to the storage state is provided by storage.getState() method.\nWriting to the storage is realized by calling functions such as storage.addConversation(), storage.addUser() etc.\nThe second argument is the **updateState** function.\nEach write to the storage performed from the service needs to call the updateState function to perform re-render.\nFor example when the service receives signalization that some user has connected, you can add user to storage using storage.addUser() method\nand next call updateState(). \n\nThis description probably looks complicated :). But believe, me it's really simple compared to when you have to take care of everything.\n\n## Basic usage\n\nThis is very simple example, but it shows how easy is it to implement a chat using **useChat** hook.\n\nFor more complex example based on CRA please visit [https://github.com/chatscope/use-chat-example](https://github.com/chatscope/use-chat-example).\nWorking example app is available here: [https://use-chat.examples.chatscope.io](https://use-chat.examples.chatscope.io)  \n\nFile: index.js\n\n```jsx\nimport {nanoid} from \"nanoid\";\nimport {\n  BasicStorage,\n  ChatProvider,\n  ExampleChatService,\n  AutoDraft\n} from \"@chatscope/use-chat\";\n\n// Storage needs to generate id for messages and groups\nconst messageIdGenerator = () =\u003e nanoid();\nconst groupIdGenerator = () =\u003e nanoid();\n\n// Create serviceFactory\nconst serviceFactory = (storage, updateState) =\u003e {\n  return new ExampleChatService(storage, updateState);\n};\n\nconst chatStorage = new BasicStorage({groupIdGenerator, messageIdGenerator});\n\nexport const App = () =\u003e {\n  return (\n    \u003cChatProvider serviceFactory={serviceFactory} storage={chatStorage} config={{\n      typingThrottleTime: 250,\n      typingDebounceTime: 900,\n      debounceTyping: true,\n      autoDraft: AutoDraft.Save | AutoDraft.Restore\n    }}\u003e\n      \u003cChat /\u003e\n    \u003c/ChatProvider\u003e\n  );\n};\n```\n\nFile Chat.js:\n\n```jsx\nimport {useState, useMemo } from \"react\";\nimport { MainContainer, Sidebar, ConversationList, Conversation, Avatar, MessageGroup, Message,\n  ChatContainer, ConversationHeader, MessageList, MessageInput} from \"@chatscope/chat-ui-kit-react\";\nimport { useChat, ChatMessage, MessageContentType, MessageDirection, MessageStatus } from \"@chatscope/use-chat\";\n\nexport const Chat = () =\u003e {\n\n  // Message input value\n  const [value, setValue] = useState(\"\");\n\n  // Get all chat related values and methods from useChat hook \n  const {\n    currentMessages, conversations, activeConversation, setActiveConversation, sendMessage, getUser\n  } = useChat();\n\n  // Get current user data\n  const [currentUserAvatar, currentUserName] = useMemo(() =\u003e {\n\n    if (activeConversation) {\n      const participant = activeConversation.participants.length \u003e 0 ? activeConversation.participants[0] : undefined;\n\n      if (participant) {\n        const user = getUser(participant.id);\n        if (user) {\n          return [\u003cAvatar src={user.avatar} /\u003e, user.username]\n        }\n      }\n    }\n\n    return [undefined, undefined];\n\n  }, [activeConversation]);\n\n  const handleSend = text =\u003e {\n\n    // Logger user (sender)\n    const currentUserId = \"123\";\n\n    const message = new ChatMessage({\n      id: \"\",\n      content: text,\n      contentType: MessageContentType.TextHtml,\n      senderId: currentUserId,\n      direction: MessageDirection.Outgoing,\n      status: MessageStatus.Sent\n    });\n\n    sendMessage({\n      message,\n      conversationId: activeConversation.id,\n      senderId: currentUserId,\n    });\n\n  };\n\n  return (\u003cMainContainer\u003e\n    \u003cSidebar position=\"left\"\u003e\n      \u003cConversationList\u003e\n        {conversations.map(c =\u003e {\n          \n          // Helper for getting the data of the first participant\n          const [avatar, name] = (() =\u003e {\n\n            const participant = c.participants.length \u003e 0 ? c.participants[0] : undefined;\n            if (participant) {\n              const user = getUser(participant.id);\n              if (user) {\n\n                return [\u003cAvatar src={user.avatar} /\u003e, user.username]\n\n              }\n            }\n\n            return [undefined, undefined]\n          })();\n\n          return (\u003cConversation key={c.id}\n                        name={name}\n                        active={activeConversation?.id === c.id}\n                        unreadCnt={c.unreadCounter}\n                        onClick={e =\u003e setActiveConversation(c.id)}\u003e\n            {avatar}\n          \u003c/Conversation\u003e);\n        })}\n      \u003c/ConversationList\u003e\n    \u003c/Sidebar\u003e\n    \n    \u003cChatContainer\u003e\n      \n      \u003cConversationHeader\u003e\n        {currentUserAvatar}\n        \u003cConversationHeader.Content userName={currentUserName} /\u003e\n      \u003c/ConversationHeader\u003e\n      \n      \u003cMessageList\u003e\n        {currentMessages.map(g =\u003e \u003cMessageGroup key={g.id} direction={g.direction}\u003e\n          \u003cMessageGroup.Messages\u003e\n            {g.messages.map(m =\u003e \u003cMessage key={m.id} model={{\n              type: \"text\",\n              payload: m.content\n            }} /\u003e)}\n          \u003c/MessageGroup.Messages\u003e\n        \u003c/MessageGroup\u003e)}\n      \u003c/MessageList\u003e\n      \n      \u003cMessageInput value={value} onSend={handleSend} /\u003e\n      \n    \u003c/ChatContainer\u003e\n    \n  \u003c/MainContainer\u003e);\n}\n```\n\n## Community and support\n\n* Twitting via [@chatscope](https://twitter.com/chatscope)\n* Chatting at [Discord](https://discord.gg/TkUYWQRf2M)\n* Facebooking at [Facebook](https://www.facebook.com/chatscope)\n* Articles on the [chatscope blog](https://chatscope.io/blog/)\n\n## Website\n\n[https://chatscope.io](https://chatscope.io)\n\n## License\n\n[MIT](https://github.com/chatscope/use-chat/blob/main/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchatscope%2Fuse-chat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchatscope%2Fuse-chat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchatscope%2Fuse-chat/lists"}