Chat is the most socially used interface in this day and age. It is the most convenient form of communication available. We all use at least one chat application daily, may it be on our mobile phones or desktop.
Haptik is one such chat service application available on Android and iOS which connects people to their very own digital personal assistants. As a user you can ask your assistant to book a movie ticket, make your dinner reservations, wake you up at 5 am in the morning, and much much more, on chat itself.
We have a team of dedicated in-house assistants who are available 24×7 to support and help the users complete these tasks.
This is why we built Athena!
Athena, named after the Greek goddess of Wisdom (we are all Greek mythology Geeks here), is Haptik’s web chat tool used by our assistants to resolve queries and complete user’s tasks. We power Athena with all the information and tool integrations that we think can make their job quicker and convenient.
The first version of Athena was made out of pure javascript and jQuery with the backend powered by Python-Django. We used Django templates for rendering HTML with jQuery being used for any DOM manipulations. This worked for us for a good 3 months, but things started blowing up soon after.
The problem with any real-time application is that things change every second. Every time a message was received we had to:
- append the messages to the thread
- update the counter of messages
- change the state of the chat
- bind new event listeners
We ended up doing heaps of expensive DOM manipulation on our app for every incoming message. To top that, our codebase was already bloated. That was the problem of using a framework like jQuery which is amorphous and unstructured, with a tightly coupled architecture. We knew we had to decouple the frontend from the backend to make it scalable.
Enter, REACT
We evaluated a bunch of frontend frameworks, with Backbone-js, Angular-js and React-js being the front-runners and finally chose the latter.
React is Facebook’s very own open source javascript library for building User Interfaces. It is the V(iew) in the traditional MVC architecture. Unlike Angular-js which has a steep learning curve, React is very easy to grasp and we started coding in days.
Here are few things we loved about React:
- JSX
React code is usually written in JSX, the extended javascript syntax programming language, using which you can write HTML type of components within Javascript. It makes the React code readable and easier to write.
<i><span style="font-weight: 400;">// MessageItem.js</span></i> <span style="font-weight: 400;">var MessageItem = React.createClass({</span> <span style="font-weight: 400;"> propTypes: {</span> <span style="font-weight: 400;"> message: ReactPropTypes.object,</span> <span style="font-weight: 400;"> },</span> <span style="font-weight: 400;"> render: function() {</span> <span style="font-weight: 400;"> var message = this.props.message;</span> <span style="font-weight: 400;"> var messageItem =</span> <span style="font-weight: 400;"> </span> <span style="font-weight: 400;"> <div className=</span> <span style="font-weight: 400;"> {cx({</span> <span style="font-weight: 400;"> 'from-assistant': message.direction == 'from-assistant',</span> <span style="font-weight: 400;"> 'from-user': message.direction == 'from-user',</span> <span style="font-weight: 400;"> })}></span> <span style="font-weight: 400;"> <div></span> <span style="font-weight: 400;"> </span> <span style="font-weight: 400;"> {message.text}</span> <span style="font-weight: 400;"> </div></span> <span style="font-weight: 400;"> </div> </span> <span style="font-weight: 400;"> return (</span> <span style="font-weight: 400;"> {messageItem} </span> <span style="font-weight: 400;"> );</span> <span style="font-weight: 400;"> },</span> <span style="font-weight: 400;">});</span> |
- One way data-binding
Unlike most frameworks, React uses a one-way data flow mechanism. React does not let the HTML to update your component. You can only use triggers and events to change the component
<span style="font-weight: 400;">// MessageComposer.js</span> <span style="font-weight: 400;">var MessageComposer = React.createClass({</span> <span style="font-weight: 400;"> getInitialState: function() {</span> <span style="font-weight: 400;"> return {text: ""};</span> <span style="font-weight: 400;"> },</span> <span style="font-weight: 400;"> _onChange: function(event,value) {</span> <span style="font-weight: 400;"> var value = event.target.value;</span> <span style="font-weight: 400;"> this.setState({text: value});</span> <span style="font-weight: 400;">},</span> <span style="font-weight: 400;"> render: function() {</span> <span style="font-weight: 400;"> return (</span> <span style="font-weight: 400;"> <div className='messageBox'></span> <span style="font-weight: 400;"> <input</span> <span style="font-weight: 400;"> type="text"</span> <span style="font-weight: 400;"> placeholder="Start Typing..."</span> <span style="font-weight: 400;"> onChange={this._onChange}</span> <span style="font-weight: 400;"> value={this.state.text}/></span> <span style="font-weight: 400;"> </div></span> <span style="font-weight: 400;"> );</span> <span style="font-weight: 400;"> },</span> <span style="font-weight: 400;">});</span> |
This is our React Message Composer component. As you can see the <input> field can only be updated via the render() function and not by the HTML itself. It can only be updated using events, in this case the onChange event.
- Component Reusability
Because of the modular nature of react, it is very easy to use and reuse the same components throughout your app.
<i><span style="font-weight: 400;">// MessageThread.js</span></i> <span style="font-weight: 400;">var MessageThread = React.createClass({</span> <span style="font-weight: 400;"> </span> <span style="font-weight: 400;">getInitialState: function() {</span> <span style="font-weight: 400;"> </span> <span style="font-weight: 400;">return {</span> <span style="font-weight: 400;"> messages: [{body:"Hey", direction:"from-user"},</span> <span style="font-weight: 400;"> {body:"I need help web checkin", direction:"from-user"},</span> <span style="font-weight: 400;"> {body:"Sure, please share your PNR", direction:"from-assistant"}],</span> <span style="font-weight: 400;"> };</span> <span style="font-weight: 400;"> },</span> <span style="font-weight: 400;"> render:function() {</span> <span style="font-weight: 400;"> var messageItems = this.state.messages.map(function(message){</span> <span style="font-weight: 400;"> return <MessageItem message={message}/></span> <span style="font-weight: 400;"> });</span> <span style="font-weight: 400;"> return(<div></span> <span style="font-weight: 400;"> {messageItems}</span> <span style="font-weight: 400;"> <MessageComposer/></span> <span style="font-weight: 400;"> </div></span> <span style="font-weight: 400;"> );</span> <span style="font-weight: 400;"> },</span> <span style="font-weight: 400;">});</span> |
The Message Item is a react component which is re-used over iteration of the message list.
- Virtual DOM
Another cool feature with React is the in-memory cache data structure that is created using javascript for updating and modifying the DOM. React computes all the changes in its cache and then updates the actual DOM. Because of this when a user messages, instead of making unnecessary and expensive DOM updations, only components like the Message, Message Counter, and other relevant components are updated.
Watch this video to learn more about React’s Virtual DOM. (source: youtube/LispCast)
Note that React is just the View part of the architecture. We use Flux by Facebook which complements React’s unidirectional flow. But, more on Flux in future posts.
Facebook announced React-Native last year, which is their framework for making hybrid native apps for iOS and Android. Since then many apps on both the stores have started converting from pure native to hybrid models. React is certainly a framework you should keep your eyes on!
If you’ve had an experience with React and would like to help us build at Haptik send in your profile at hello@haptik.co and join the react team! 🙂
P.S: If you want to connect the dots on this post, simply Download Haptik & you’ll know what the hell we were talking about.