.DS_Store
# # Introduction to Reactive Programming
_By André Staltz_

![](https://d2eip9sf3oo6c2.cloudfront.net/series/square_covers/000/000/020/full/EGH_IntrotoReactive.png?1496436376)

"Reactive"
You've probably been hearing this word recently. Reactive Programming has you curious, and you want to dig in and start learning what it is all about.
What's the most difficult aspect of Reactive Programming? Thinking Reactive!
In this series, we will discover what it means to think Reactive through RxJS. We will exercise our minds, and let go of our old imperative and stateful habits of programing.
If you are brand new to reactive programming, watch this series first.
body {
    font-family: sans-serif;
    padding: 10px;
}
h3 {
    font-weight: bold;
    display: inline-block;
  padding: 0;
  margin: 0;
}
.refresh {
    font-size: 80%;
    margin-left: 10px;
}
.header {
    background: #ECECEC;
    padding: 5px;
}
.suggestions {
    border: 2px solid #ECECEC;
}
li {
    padding: 5px;
}
li img {
    width: 40px;
    height: 40px;
    border-radius: 20px;
}
li .username, li .close {
    display: inline-block;
    position: relative;
    bottom: 15px;
    left: 5px;
}
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="app.css">
  <meta charset="utf-8">
</head>
<body>
<div class="container">
    <div class="header">
         <h3>Who to follow</h3><a href="#" class="refresh">Refresh</a>
    </div>
    <ul class="suggestions">
        <li class="suggestion1">
            <img />
            <a href="#" target="_blank" class="username">this will not be displayed</a>
            <a href="#" class="close close1">x</a>
        </li>
        <li class="suggestion2">
            <img />
            <a href="#" target="_blank" class="username">neither this</a>
            <a href="#" class="close close2">x</a>
        </li>
        <li class="suggestion3">
            <img />
            <a href="#" target="_blank" class="username">nor this</a>
            <a href="#" class="close close3">x</a>
        </li>
    </ul>
</div>
    <script src="https://code.jquery.com/jquery-1.7.2.js"></script>
    <script src="https://unpkg.com/rxjs@5.4.3/bundles/Rx.min.js"></script>
    <script src="script.js"></script>
</body>
</html>
var refreshButton = document.querySelector('.refresh');
var closeButton1 = document.querySelector('.close1');
var closeButton2 = document.querySelector('.close2');
var closeButton3 = document.querySelector('.close3');

var refreshClickStream = Rx.Observable.fromEvent(refreshButton, 'click');
var close1Clicks = Rx.Observable.fromEvent(closeButton1, 'click');
var close2Clicks = Rx.Observable.fromEvent(closeButton2, 'click');
var close3Clicks = Rx.Observable.fromEvent(closeButton3, 'click');

var startupRequestStream = Rx.Observable.of('https://api.github.com/users');

var requestOnRefreshStream = refreshClickStream
  .map(ev => {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  });

var requestStream = startupRequestStream.merge(requestOnRefreshStream);

var responseStream = requestStream
  .flatMap(requestUrl =>
    Rx.Observable.fromPromise(jQuery.getJSON(requestUrl))
  )
  .publishReplay().refCount(1);

// refreshClickStream: -------f------------->
// requestStream:      r------r------------->
// responseStream:     ---R-------R--------->
// closeClickStream:   ---------------x----->
// suggestion1Stream:  N--u---N---u---u----->

function getRandomUser(listUsers) {
  return listUsers[Math.floor(Math.random()*listUsers.length)];
}

function createSuggestionStream(responseStream, closeClickStream) {
  return responseStream.map(getRandomUser)
    .startWith(null)
    .merge(refreshClickStream.map(ev => null))
    .merge(
      closeClickStream.withLatestFrom(responseStream, 
                                  (x, R) => getRandomUser(R))
    );
}

var suggestion1Stream = createSuggestionStream(responseStream, close1Clicks);
var suggestion2Stream = createSuggestionStream(responseStream, close2Clicks);
var suggestion3Stream = createSuggestionStream(responseStream, close3Clicks);

// Rendering ---------------------------------------------------
function renderSuggestion(suggestedUser, selector) {
  var suggestionEl = document.querySelector(selector);
  if (suggestedUser === null) {
    suggestionEl.style.visibility = 'hidden';
  } else {
    suggestionEl.style.visibility = 'visible';
    var usernameEl = suggestionEl.querySelector('.username');
    usernameEl.href = suggestedUser.html_url;
    usernameEl.textContent = suggestedUser.login;
    var imgEl = suggestionEl.querySelector('img');
    imgEl.src = "";
    imgEl.src = suggestedUser.avatar_url;
  }
}

suggestion1Stream.subscribe(user => {
  renderSuggestion(user, '.suggestion1');
});

suggestion2Stream.subscribe(user => {
  renderSuggestion(user, '.suggestion2');
});

suggestion3Stream.subscribe(user => {
  renderSuggestion(user, '.suggestion3');
});