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
- Connections
- Disconnections
- Username changes
- Messages
- 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