Giới thiệu RxJS và Redux Observer

Những khái niệm chính cần hiểu khi làm việc với RxJS

  • Observable một interface sẽ lắng nghe những notification trong một khoản thời gian và push cho những interface khác sẽ làm gì đó khi có notification này.
  • Subscription Khi observable bắt đầu được thực thi, ví dụ như lắng nghe sự kiện, và push
  • Observer một interface sẽ làm gì đó với data được push từ observable
  • Operators các phương thức được sử dụng để tương tác với output của Observable

Ví dụ đăng ký listen lên một sự kiện nào đó

const button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked'));

Trong RxJS chúng ta viết như sau

var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .subscribe(() => console.log('Clicked!'));

Khởi tạo Observable

Chúng ta có thể tạo observable bằng cách convert từ

một hoặc nhiều giá trị

Rx.Observable.from([1,2,3]);

Từ một sự kiện

Rx.Observable.fromEvent(document.querySelector('button'), 'click');

Từ một promise

Rx.Observable.fromPromise(fetch('/users'));

Chúng ta cũng có thể tạo observable sử dụng Observable.create

var foo = Rx.Observable.create(function (observer) {
  observer.next(42);
  observer.next(100);
  observer.next(200);
  setTimeout(() => {
    observer.next(300);
  }, 1000);
  observer.complete();
});

foo.subscribe(function(x) {
  console.log(x);
});

Để ý là observer có phương thức nextcomplete.

mergeMap ( alias là flatMap)

Phương thức phổ biến nhất cho phép transform output của observable.

<input type='text' id='input1' />
<input type='text' id='input2' />
<p>Combined value: <span></span></p>

Nếu chúng ta muốn subscribe lên sự kiện user input giá trị vô <input/>

var input1 = document.querySelector('#input1');
var input2 = document.querySelector('#input2');
var span = document.querySelector('span');

var obs1 = Rx.Observable.fromEvent(input1, 'input')
  .subscribe(event => span.textContext = event.target.value);

var obs2 = Rx.Observable.fromEvent(input2, 'input')
  .subscribe(event => span.textContext = event.target.value);

Giá trị span sẽ thay đổi khi ta nhập giá trị cho 1 trong 2 input, tuy nhiên nó sẽ override giá trị cũ. Nếu muốn có một kết quả combine từ cả 2 giá trị nhập vào từ input, ta mergeMap 2 observable lại.

var obs1 = Rx.Observable.fromEvent(input1, 'input');
var obs2 = Rx.Observable.fromEvent(input2, 'input');

obs1.mergeMap(
  event1 => {
    return obs2.map(event2 => event1.target.value + ' ' + event2.target.value)
  }
).subscribe(
  combineValue => span.textContext = combineValue
);

Redux-Observable

Redux-Observable cho phép chúng ta đưa các khái niệm của RxJS vào trong Redux. Nó sẽ tạo ra các Observable lắng nghe action, xào nấu trước khi dispatch một action khác đến reducer. Nó được gọi một cái tên chảnh chó là Epic (mình gọi nó là chảnh chó vì mình thấy nó méo có gì để được gọi là epic cả)

import { ajax } from 'rxjs/observable/dom/ajax';

// Action creators
const fetchUser = username => ({ type: 'FETCH_USER', payload: username });
const fetchUserFulfilled = payload => ({ type: 'FETCH_USER_FULFILLED', payload });

// Epic
const fetchUserEpic = action$ =>
  action$.ofType('FETCH_USER')
    .mergeMap(action =>
      ajax.getJSON(`https://api.github.com/users/${action.payload}`)
        .map(response => fetchUserFulfilled(response))
    );
// Dispatch FETCH_USER action
dispatch(fetchUser('torvalds'));

Khi action type FETCH_USER được dispatch ra, fetchUserEpic lắng nghe tất cả sự kiện, nếu type là FETCH_USER, nó không đưa ngay xuống reducer của redux mà dừng lại và gọi ajax, sau khi có kết quả ajax, nó lại dispatch ra một sự kiện khác với type là FETCH_USER_FULFILLED, rồi trả về cho reducer

Link bài gốc Video giải thích mergeMap