Using the UI framework (web only)
Mitter's standard component library (scl) makes it even easier to get started building your messaging apps. Unlike the platform and the SDK, the SCL takes a very opinionated approach to the various (often repeated) components of a messaging application.
Currently the SCL is in beta and is distributed for web platforms only. Since the SCL is primarily a UI framework, each edition of the framework is tied to a UI library. Currently one edition of the SCL is available, for React projects.
Installation
To add the scl to your project, simply use yarn
or npm
or
Before you begin make sure that your base project is setup as described here
Adding a managed Message list
In the getting started application we had the ability to send and receive messages. We were using a simple listener that would listen on any new messages coming to the channel and displaying them as a list of UI components. However, there are a few issues with the same:
All previous messages are lost if the page is reloaded
If we were to make a network call and get the previous messages that would be a sub-optimal experience as we would want to fetch only the messages that the user is interested in (preferably when they scroll up)
If were to do that as well, we still don't want to generate a DOM element for every single message that was loaded - a channel could have upto thousands of messages and it could make your application extremely slow and bloated.
For this purpose, the SCL bundles in a component MessageListManager
that takes care of all of the above along with some more nifty features for fine-grained control over message rendering.
In the following example, we will continue modifying the mitter-web-starter
and use a message list from recat-scl
instead.
You can checkout the final completed app:
Creating a message view producer
Before we can start using the MessageListManager
we need to be able to tell the manager how to render individual messages. To do so, we'll start with creating a message component:
A message view producer takes two lambdas - the first one is a predicate which for a given message dictates if the current view will be used to render the message and the second returns the rendered component. In our case we are setting our predicate to always return true
since we want to use the same producer for all messages.
NOTE The above is code adapted from the
mitter-web-starter
package which you can use as a starting point to test out SCL.
Displaying messages
With a message view producer in place, we can now use the MessageListManager
component. An example is as shown below:
In the above example we are basically re-writing the renderMessages
function. The various props passed to the component are:
messages
This is a list of messages that are to be rendered. This can be a reference to the entire message list if required, or only a subset that is available. The MessageListManager
uses a virtualized list that will create DOM elements for only the messages that are visible.
defaultView
This is the view producer used when there is no other view available. Do note that we don't directly use the view producer, but instead use .produceView
function on it. This is because defaultView
does not perform any predicate checking and expects only rendering to be performed.
producers
are a list of producers used to render messages. To render a particular message all producers are run (in insertion order) till one of their predicates returns true
. If no such producer is found, then the defaultView
is used.
An onEndCallback
is a function called when new messages are to be fetched. We will shortly look into how to use this callback.
Till this point, everything would be working exactly like the mitter-web-starter
. In terms of functionality we haven't really added anything else. Let's now add a PaginationManager
to handle various events where the messages would be populated.
Adding a Pagination Manager
A PaginationManager
is a construct available in the @mitter-io/core
module which makes it easy to consume paginated APIs (like /v1/channels/{}/messages
, /v1/channels
) etc.
For our message list we need to do the following:
Get the first page of messages whenever the component for a list of messages belonging to a particular channel is loaded.
Get the previous page from the scroll point that the user scrolls up to.
Since we are maintaining a list of messages in our parent component, we will initiate the process of fetching the first list of messages in it's setChannels
method (which in turn is called by componentDidMount
).
Let's first modify the state to store our PaginationManager
(this is required because pagination managers maintain state regarding which page they are on and hence should be persisted across the component lifecycle):
Now when we get a list of channels, we want to create a pagination manager for the messages of each channel:
And then we'll write a function to fetch the first page of messages for a given channel:
And then we'll call it on the first page load:
Try reloading the page now and you'll see that the latest few messages (by default 45) are automatically loaded in the message window.
However, when we scroll to the top, no new messages are loaded. For that we need to make simply make sure that this.fetchPreviousPage
is called when the user scrolls to the top. To do so, pass on the method as a prop down to the MessageListManager
:
In App.js,
Check the last prop that was added. And then pass this function to the onEndCallback
prop in MessageListManager
And that's all you have to do. Try scrolling up the window:
Adding a loader
If you tried out the application, you'd notice that when the user scrolls up there is a small delay before the previous messages are loaded. While this is happening, you might want to show a small loading icon/progress bar to the user. To do so, you have to set two props on the MessageListManager
Whenever isLoading
is true, the message list will display the component returned by loader
in the top area where the new messages would be appended.
Last updated