Chat JavaScript v3
Chat JavaScript
Chat
JavaScript
Home
/
Chat
/
JavaScript
/
Local caching
New Docs for the latest Chat SDK v4 for JavaScript is now available.Go to v4

Migration from SyncManager

Local caching is available with Sendbird Chat SDK. Both local caching and SyncManager enables Sendbird Chat SDK for Javascript to locally cache and retrieve data related to group channels and messages. However, local caching is integrated into Chat SDK while SyncManager is an external add-on. Being internally integrated into Chat SDK allows for easier maintenance, improved stability, and enhanced usability.

The existing SyncManager for Javascript will be deprecated soon, so it is highly recommended to migrate from SyncManager to the Chat SDK with local caching. In the meantime, SyncManager will continue to work if the dependency to SyncManager is not removed. The dependency should be deleted once the migration to local caching is completed.


Initialization

There are two ways to initialize the Chat SDK, with local caching or without local caching. During the initialization, the localCacheEnabled determines whether the client app will use local caching with Sendbird Chat SDK or not. Its default value is false meaning Chat SDK will be initialized without local caching.

Note: If initialization fails to complete while the localCacheEnabled is set to true, the Chat SDK will operate as if the localCacheEnabled is set to false.

Connect to Sendbird server

SyncManager's SendBirdSyncManager.setup() that was called after the new SendBird during the initialization process is changed to initializeDatabase() in local caching. When connecting to Sendbird server, it internally calls initializeDatabase() so that the initialization is done along with the database set up. Functionality wise, local caching's initializeDatabase() does the same thing as SyncManager's SendBirdSyncManager.setup(). It ensures that your client app is operational during offline mode.

Local cachingSyncManager
// Initialize with the localCacheEnabled set to true.
const sendbird = new SendBird({ appId: APP_ID, localCacheEnabled: true });

Group channel collection

A groupChannelCollection allows you to swiftly create a channel list without missing any channel-related updates by retrieving group channels from both the local cache and Sendbird server. This page explains how to make a channel list using the collection and serves as a migration guide.

Create a collection

SyncManager's ChannelCollection is changed to the groupChannelCollection in local caching. The groupChannelCollection instance can be created through the createChannelCollection() method. When creating the instance, you can also determine how to filter and order the group channel list.

Local cachingSyncManager
const groupChannelFilter = new sendbird.GroupChannelFilter();
groupChannelFilter.includeEmpty = INCLUDE_EMPTY;

const groupChannelCollection = sendbird.GroupChannel.createGroupChannelCollection()
  .setOrder(ORDER)
  .setFilter(groupChannelFilter)
  .setLimit(LIMIT)
  .build();

Channel events

In local caching, the groupChannelCollectionHandler is used to determine how the client app would react to channel-related events. SyncManager's handler.onChannelEvent, which is used to handle real-time events, should be changed as shown in the code below.

The following table shows when to call each event handler.

EventDescription

onChannelAdded

- Called when a new group channel is created as a real-time event.
- New group channels are fetched by changelog sync.
- It replaces SyncManager's insert action.

onChannelUpdated

- Called when the channel information that is included in the user's current chat view is updated as a real-time event.
- Updated channel information is fetched during changelog sync.
- It replaces SyncManager's update and move actions.

onChannelDeleted

- Called when a group channel is deleted as a real-time event.
- A channel deletion event is fetched during changelog sync.
- It replaces SyncManager's remove action.

Local cachingSyncManager
channelCollection.setGroupChannelCollectionHandler({
  onChannelsAdded: (context, channels) => {
  },
  onChannelsUpdated: (context, channels) => {
  },
  onChannelsDeleted: (context, channelUrls) => {
  },
});

List channels

SyncManager's fetch() method retrieves channels from the local cache and delivers them to the ChannelCollectionHandler instance. In local caching, the groupChannelCollection can retrieve channels through two new interfaces, hasMore and loadMore().

By default, cached channels are listed in reverse chronological order, meaning the channel that most recently received a message appears at the top of the list. The channel order is automatically updated in the local cache when a new message arrives.

MethodDescription

hasMore

- Checks if there are more channels to load.
- Called whenever a user scroll reaches the top or bottom of the channel list depending on the implementation.

loadMore()

- If hasMore is true, retrieves channels from the local cache to show in the channel list.
- Called whenever a user scroll reaches the top or bottom of the channel list depending on the implementation.

Local cachingSyncManager
if (groupChannelCollection.hasMore) {
  groupChannelCollection.loadMore()
    .then(channels => {
      //...
    })
    .catch(error => {
      // Handle error.
    });
}

Dispose of the collection

SyncManager's ChannelCollection has the remove() method that clears all the channels managed by the collection and stops synchronization process of the collection.

On the other hand, local caching uses the dispose() method to clear the existing channel list view. This method should be called when the user closes the channel list so that the groupChannelCollectionHandler won't make any change to the channel list.

Local cachingSyncManager
groupChannelCollection.dispose();

Message collection

A MessageCollection allows you to swiftly create a chat view without missing any message-related updates by retrieving data from both the local cache and Sendbird server. This page explains how to create a chat view using the collection and serves as a migration guide.

Create a collection

Create a MessageCollection through the createMessageCollection() method. Use the new sendbird.MessageFilter() to set the message order and then, specify the starting point of the message list in the chat view using the collection's builder.

Local cachingSyncManager
const messageFilter = new sendbird.MessageFilter();
messageFilter.messageType = MESSAGE_TYPE;
let messageCollection = channel.createMessageCollection()
  .setFilter(messageFilter)
  .setStartingPoint(STARTING_POINT)
  .setLimit(LIMIT)
  .build();

Message events

Use the messageCollectionHandler to determine how the client app would react to message-related events.

A new addition to local caching is onHugeGapDetected. If more than 300 messages are missing in the local cache compared to the remote server, Sendbird Chat SDK determines that there is a huge gap. For further information, see Gap and synchronization.

The following table shows when to call each event handler.

HandlerCalled when

onMessageAdded

- A new message is created as a real-time event.
- New messages are fetched through the gap check API.

onMessageDeleted

- A message is deleted as a real-time event.
- Message deletion is detected during changelog sync.

onMessageUpdated

- A message is updated as a real-time event.
- Message update is detected during changelog sync.
- The status of a message changes.

onChannelUpdated

- The channel information that is included in the user's current chat view is updated as a real-time event.
-Channel info update is detected during changelog sync.

onChannelDeleted

- The current channel is deleted as a real-time event.
- Channel deletion is detected during changelog sync.
- In both cases, the entire view should be disposed of.

onHugeGapDetected

- A huge gap is detected when more than 300 messages are missing in the local cache compared to the remote server. In this case, you need to dispose of the view and create a new messageCollection instance.

SyncManager's onSucceededMessageEvent() should be changed as shown in the code below.

Local cachingSyncManager
messageCollection.setMessageCollectionHandler({
   /**
    * SyncManager's following events should be handled through the onMessagesAdded in local caching:
    *   1. onSucceededMessageEvent()'s `insert` action.
    *   2. onPendingMessageEvent()'s `insert` action when sending a message.
    */
  onMessagesAdded: (context, channel, messages) => {
    // ...
  },
  /**
    * SyncManager's following events should be handled through the onMessagesUpdated in local caching:
    *   1. onSucceededMessageEvent()'s `update` action.
    *   2. onPendingMessageEvent()'s `insert` action when resending a failed message.
    *   3. onFailedMessageEvent()'s `insert` action when sending or resending a message failed.
    */
  onMessagesUpdated: (context, channel, messages) => {
    // ...
  },
  /**
    * SyncManager's following events should be handled through the onMessagesDeleted in local caching:
    *   1. onSucceededMessageEvent()'s `remove` action.
    *   2. onFailedMessageEvent()'s `remove` action.
    */
  onMessagesDeleted: (context, channel, messages) => {
    // ...
  },
    /**
    * The onChannelEvents()'s update action should be handled through the onChannelUpdated in local caching.
    */
  onChannelUpdated: (context, channel) => {
    // ...
  },
  /**
    * The onChannelEvent()'s remove action should be handled through the onChannelDeleted() in local caching.
    */
  onChannelDeleted: (context, channel) => {
    // ...
  },
   /**
    * The onHugeGapDetected is called when the SDK detects more than 300 messages missing when connected.
    * The current message collection should be disposed and a new MessageCollection is created.
    */
  onHugeGapDetected: () => {
    // ...
  },
});

SyncManager's messageCollectionHandler.onNewMessage used to notify a new message that had arrived should also be changed with the code below.

Local cachingSyncManager
const channelHandler = new sendbird.ChannelHandler();
channelHandler.onMessageReceived = (channel, message) => {
  // There's no new message for this channel.
};
sendbird.addChannelHandler(CHANNEL_HANDLER_KEY, channelHandler);

List messages

SyncManager's fetchSucceededMessages() method retrieves messages from the local cache and delivers them to the MessageCollectionHandler instance. In local caching, the MessageCollection can retrieve messages through five new interfaces, initialize(), hasPrevious, hasNext, loadPrevious(), and loadNext().

Unlike the GroupChannelCollection, pagination works in both direction for messages because messages can be shown in either chronological or reverse chronological order depending on how you set the value of startingPoint.

MethodDescription

hasPrevious

- Checks if there are more messages to load from the previous page.
- Called whenever a user scroll hits the top or bottom of the chat view, depending on the implementation.

loadPrevious()

- If hasPrevious is true, retrieves messages from the local cache to show in the view.
- Called whenever a user scroll hits the top or bottom of the chat view, depending on the implementation.

hasNext

- Checks if there are more messages to load in the next page.
- Called whenever a user scroll hits the top or bottom of the chat view, depending on the implementation.

loadNext()

- If hasNext is true, retrieves messages from the local cache to show in the view.
- Called whenever a user scroll hits the top or bottom of the chat view, depending on the implementation.

Policy

In a MessageCollection, the initialization is dictated by the MessageCollectionInitPolicy. The MessageCollectionInitPolicy determines how initialization deals with the message data retrieved from the local cache and API calls. Because we only support CACHE_AND_REPLACE_BY_API at this time, an additional implementation is required to clear the messages in the local cache before adding the messages from the remote server. Messages will first be retrieved from the cached list using the .onCacheResult(). Next, the .onApiResult() calls the API result list which then replaces the cached message list with messages received from the API call.

Local cachingSyncManager
// Initialize messages from the startingPoint.
sendbird.setErrorFirstCallback(true);
let initPolicy = sendbird.MessageCollection.MessageCollectionInitPolicy.CACHE_AND_REPLACE_BY_API;
messageCollection.initialize(initPolicy)
    // Messages will be retrieved from the local cache.
    // They might be too outdated compared to the startingPoint.
  .onCacheResult((error, messages) => {
    if (error) {
      // Handle error.
    }
    // ...
  })
  .onApiResult((error, messages) => {
    if (error) {
      // Handle error.
    }
    // ...
  });

// Next direction
if (messageCollection.hasNext) {
  messageCollection.loadNext()
    .then(messages => {
      // ...
    })
    .catch(error => {
      // Handle error.
    });
}

// Previous direction
if (messageCollection.hasPrevious) {
  messageCollection.loadPrevious()
    .then(messages => {
      // ...
    })
    .catch(error => {
      // Handle error.
    });
}

SyncManager's resetViewpointTimestamp is used to reset the current message collection to the specified time. To reset a viewpoint timestamp in local caching, it is suggested that you dispose the current message collection and create a new collection.

Local cachingSyncManager
messageCollection.dispose();
messageCollection = channel.createMessageCollection()
  .setFilter(messageFilter)
  .setStartingPoint(messageCollection.startingPoint)
  .setLimit(LIMIT)
  .build();
messageCollection.initialize(MESSAGE_COLLECTION_INIT_POLICY)
  .onCacheResult((error, messages) => {
    if (error) {
      // Handle error.
    }
    // ...
  })
  .onApiResult((error, messages) => {
    if (error) {
      // Handle error.
    }
    // ...
  });

Send a message

In local caching, the result of sending a message is handled internally through the MessageCollectionHandler. First, pending messages are delivered to local caching's MessageCollectionHandler.onMessagesAdded(). Whether the message succeeds or fails in sending, the result will be delivered to the MessageCollectionHandler.onMessagesUpdated(). Thus, the process of using a callback from the sendUserMessage() and sendFileMessage() to manually input the send result in SyncManager is no longer needed.

Note: Don't add the pending, succeeded or failed message objects of the sendMessage() callback to your message list data source. This can cause duplicate messages in the chat view.

Local cachingSyncManager
// User Message
channel.sendUserMessage(USER_MESSAGE_PARAMS, (error, message) => {
});

// File Message
channel.sendFileMessage(FILE_MESSAGE_PARAMS, (error, message) => {
});

Resend a failed message

In local caching, the result of resending a message is handled internally through the MessageCollectionHandler. First, pending messages are delivered to local caching's MessageCollectionHandler.onMessagesUpdated(). Whether the message has succeeded or failed in sending, the result will be delivered to the MessageCollectionHandler.onMessagesAdded(). Thus, the process of using a callback from the resendMessage() to manually input the send result in SyncManager is no longer needed.

Note:Don't add the pending, succeeded or failed message objects of the resendMessage() callback to your message list data source. This can cause duplicate messages in the chat view.

Local cachingSyncManager
// User Message
channel.resendUserMessage(failedMessage, (error, message) => {
});

// File Message
channel.resendFileMessage(failedMessage, (error, message) => {
});

// Pending Messages
//This should be called after the messageCollection.start(with:cacheResultHandler:apiResultHandler:).
const pendingMessages = messageCollection.pendingMessages;

// Failed Messages
//This should be called after the messageCollection.start(with:cacheResultHandler:apiResultHandler:).
const failedMessages = messageCollection.failedMessages;

Update a message

SyncManager uses the MessageCollections updateMessage() callback to manually update a message in collection after updating the same message in a channel. In local caching, however, updating message is handled internally and delivered to the MessageCollectionHandler.onMessagesUpdated().

Local cachingSyncManager
channel.updateUserMessage(message.messageId, userMessageParams, (error, message) => {
});

Delete a message

There are two cases in deleting a message:

Deleting a sent message.

In SyncManager, the process of delivering the result of message deletion through the deleteMessage() is required. However, this process is not needed in local caching.

Deleting a failed message.

The process is the same for both SyncManager and local caching where the failed message object is deleted explicitly from the local cache. In SyncManager, failed messages are deleted through the deleteMessage(). The same can be done through the removeFailedMessages() in local caching.

Local cachingSyncManager
// 1. Deleting a succeeded message.
channel.deleteMessage(message, error => {
  /**
   * The result will be delivered to the `MessageCollectionHandler.onMessagesDeleted()`.
   */
});

// 2-1. Deleting a failed message. Delete it from the collection only.
messageCollection.removeFailedMessages(failedMessages)
  .then(requestIds => {
    // ...
  })
  .catch(error => {
    // Handle error.
  });

// 2-2. Deleting all failed messages. Delete it from the collection only.
messageCollection.removeAllFailedMessages()
  .then(() => {
    // ...
  })
  .catch(error => {
    // Handle error.
  });

Dispose of the collection

SyncManager's MessageCollection has a remove() method that clears all the messages managed by the collection and stops synchronization processes in the collection instance.

On the other hand, local caching uses the dispose() method to clear the existing chat view. You should call this method when the current user leaves the channel or when a new collection has to be created due to a huge gap detected by the onHugeGapDetected().

Local cachingSyncManager
messageCollection.dispose();

Other methods

Local caching's sendbird.clearCachedMessages is used to clear cached messages in a specified channel. It will replace SyncManager's clearCache() which clears the entire data file. Local caching's sendbird.clearCachedMessages must be called after sendbird.initializeDatabase().

Local cachingSyncManager
sendbird.clearCachedMessages(CHANNEL_URLS)
  .then(() => {
    // ...
  })
  .catch(error => {
    // Handle error.
  });

In addition, SyncManager's messageCollection.messageCount is replaced with the functionality of the messageCollection.succeededMessages.length in local caching. It is used to count the number of succeeded messages in the collection.

Local cachingSyncManager
// The messageCollection provides a getter for the current message list in the message collection.
const messageCount = messageCollection.succeededMessages.length;