Reactive Programming in JavaScript

Javascript is all about

Events

Reactive programming thrives on these events

So what is Reactive programming?

  • Designing your app around asynchronous data streams
  • Specify "what" rather than "how"
  • Declare your app as a cascading set of dependencies

JavaScript

  • Native language of the web
  • Incredible opportunities to experiment with RP style. 

JavaScript

View Layer

Data Layer

React

RxJS

React

  • View layer
  • Virtual DOM
  • Data Flow

RxJS

  • A JS library for composing and consuming asynchronous data streams.
  • Can hook into UI events and Node.js Event Emitter

Demo

The View Layer

Reacting to Username Changes

Everything is a component pure function

<!-- app.js -->

<div className="row">
  <ChatRoster 
    onCurrentUserChange={this.onCurrentUserChange} 
    users={this.state.users}
    currentUser={this.state.currentUser}
    lastMessage={this.state.lastMessage} />
  {
    currentUser
    ? 
    <ChatBox 
      currentUser={this.state.currentUser}
      myUsername={this.state.myUsername}
      onMessageSent={this.onMessageSent}
      messages= {this.state.messages[currentUser]} />
    :
    <div />
  }
</div>
<ChatRoster />
<ChatBox />

Reacting to Username Changes

Use the props

<!-- chat-roster.js -->

<div className="list-group">
  {
    this.props.users.map(function(user) {
      var unreadNotifications = that.state.unreadNotifications[user];
      return (
        <a data-user={user} 
            className={"list-group-item" + (user === currentUser ? ' active' : '')}
            onClick={that.onUserSelect}
            key={user}>
          {user}
          {unreadNotifications ? 
            <span className="badge">{unreadNotifications}</span> : 
            <div />}
        </a>
      )
    })
  }
</div>

The Data Layer

  1. Connections
  2. Disconnections
  3. Username changes
  4. Messages
  5. Typing

Functionality

Online Users

var appInitStream = ChatServer.initStream;

var connectionsStream = ChatServer.connections()
  .map(function(username) {return {op: 'Add', username: username}});

var disconnectionsStream = ChatServer.disconnections()
  .map(function(username) {return {op: 'Remove', username: username}});

var usernameChangeStream = ChatServer.usernameChanges()
  .map(function(change) {
    return _.extend(change, {op: 'Change'});
  })

var userEventsStream = Rx.Observable
  .merge(connectionsStream, disconnectionsStream, usernameChangeStream);

var onlineUsersStream = appInitStream.pluck('users')
  .merge(userEventsStream)
  .scan(function(users, ev) {
    switch (ev.op) {
      case 'Add':
        return users.concat(ev.username);
      case 'Remove':
        return _.without(users, ev.username);
      case 'Change':
        users[users.indexOf(ev.old_username)] = ev.new_username;
        return users;
    }

    return users;
  });

Functionality

Typing

var isTypingStream = ChatServer
  .typing()
  .filter(function(user) {return user == that.props.currentUser})
  .map(function() {return true});

var notTypingStream = isTypingStream
  .debounce(1500)
  .map(function() {return false});

var typingStream = Rx.Observable
    .merge(isTypingStream, notTypingStream);

typingStream.forEach(function(isTyping) {
  that.setState({typing: isTyping})
});

Functionality

In conclusion...

  • Modularity
  • Flexibility
  • Readability
  • Separation of concerns

We think we acheived:

Questions ?

Fin.

Reactive Programming in JavaScript

By Swapneel Desai

Reactive Programming in JavaScript

  • 606