RxJS ์ ๋ฌธ
RxJS๊ฐ ์ฒ์์ด์ ๊ฐ์? ์ด ๋ฌธ์์์๋ RxJS์ ๋ํด ํ์ ํ๊ธฐ ์ํด ํ์ํ ์ฃผ์ ๊ฐ๋ ์ ๋ค๋ฃน๋๋ค. ๊ฝ ์ก์ผ์๊ณ , ์์ํฉ๋๋ค!
Observable(์ต์ ๋ฒ๋ธ)์ด ๋ฌด์์ธ๊ฐ์?
์ต์ ๋ฒ๋ธ์ ์๊ฐ์ ๋ฐ๋ผ ํ๋ฅด๋ ์คํธ๋ฆผ(stream) ๋๋ ๋ฐ์ดํฐ ๊ฐ์
๋๋ค. ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ ์ต์ ๋ฒ๋ธ๋ก ๋ง๋ค ์ ์์ง๋ง, RxJS์์์ ์ผ๋ฐ์ ์ธ ํ์ฉ ์์๋ ์ด๋ฒคํธ์
๋๋ค. ์ด ์ด๋ฒคํธ๋ ๋ง์ฐ์ค ์ด๋, ๋ฒํผ ํด๋ฆญ, ํ
์คํธ ํ๋ ์
๋ ฅ์ด๋ ๋ผ์ฐํธ ๋ณ๊ฒฝ ๋ฑ ๋ฌด์์ด๋ ๋ ์ ์์ฃ . ์ต์ ๋ฒ๋ธ์ ๋ง๋๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ๋ด์ฅ creation ํจ์๋ฅผ ์ด์ฉํ๋ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด,fromEvent
๋ผ๋ ๋ด์ฅ ํจ์๋ฅผ ์ด์ฉํด ๋ง์ฐ์ค ํด๋ฆญ ์ด๋ฒคํธ ์ต์ ๋ฒ๋ธ์ ๋ง๋ค ์ ์์ต๋๋ค.
// fromEvent ์ฐ์ฐ์ import
import { fromEvent } from 'rxjs';
// button ์๋ฆฌ๋จผํธ ์ฐธ์กฐ
const button = document.getElementById('myButton');
// button ํด๋ฆญ ์ต์ ๋ฒ๋ธ ์์ฑ
const myObservable = fromEvent(button, 'click');
์ง๊ธ ์ฐ๋ฆฌ์๊ฒ ์๋ ์ด ์ต์ ๋ฒ๋ธ์ ์๋ฌด๊ฒ๋ ํ์ง ์์ต๋๋ค. ์ด๋ ์ต์ ๋ฒ๋ธ์ด "์ฐจ๊ฐ๊ฑฐ๋", ํ์ฑํ๋์ง ์์๊ธฐ ๋๋ฌธ์ ๋๋ค(์: ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ฐ๊ฒฐ). ์ด๊ฒ ์ ๊น์ง๋ ๋ง์ด์ฃ ...
Subscription(๊ตฌ๋
)
๊ตฌ๋
์ ๋ชจ๋ ๊ฒ์ ์์ง์ด๋ ์๋๋ ฅ์
๋๋ค. ๋๊ตฐ๊ฐ ์์ก์ด๋ฅผ ๋๋ฆฌ๊ธฐ๋ง ํ๋ฉด ๋์ฌ ์ค๋น๊ฐ ๋์ด์๋ ๋ฌผ์ค๊ธฐ(์ต์ ๋ฒ๋ธ)์ ์๋๊ผญ์ง ๊ฐ์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ํธํฉ๋๋ค. ์ต์ ๋ฒ๋ธ์ ๊ฒฝ์ฐ, ์์ก์ด๋ฅผ ๋๋ฆฌ๋ ์ญํ ์ subscriber(๊ตฌ๋
์)
์๊ฒ ์ฃผ์ด์ง๋๋ค.
๊ตฌ๋
์ ์์ฑํ๋ ค๋ฉด observer(์ต์ ๋ฒ)
๋ผ๊ณ ํ๋ ํจ์ ๋๋ ๊ฐ์ฒด๋ฅผ ์ ๊ณตํ๋ subscribe
๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ์ฌ๊ธฐ์ ๊ฐ ์ด๋ฒคํธ์ ๋ํ ๋ฐ์(-ํ ํ๋ก๊ทธ๋๋ฐ) ๋ฐฉ๋ฒ์ ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
// fromEvent ์ฐ์ฐ์ import
import { fromEvent } from 'rxjs';
// button ์๋ฆฌ๋จผํธ ์ฐธ์กฐ
const button = document.getElementById('myButton');
// button ํด๋ฆญ ์ต์ ๋ฒ๋ธ ์์ฑ
const myObservable = fromEvent(button, 'click');
// ์ด์ ๊ฐ ํด๋ฆญ ์ด๋ฒคํธ์ ๋ํ ๋ก๊ทธ๋ฅผ ์ฐ์ด๋ด
์๋ค.
const subscription = myObservable.subscribe(event => console.log(event));
์์ ์์์์ myObservable.subscribe()
๋
ํด๋ฆญ ์ด๋ฒคํธ๋ฅผ ์ํ ๋ฒํผ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ค์ ํ๊ณ
ํด๋ฆญ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ๊ตฌ๋ ๋ฉ์๋(์ต์ ๋ฒ)์ ์ ๋ฌํ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
์ ์ ํ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ ๊ฑฐํ๋ ๊ฒ์ฒ๋ผ,
unsubscribe()
๊ฐ ํฌํจ๋ ๊ตฌ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
์ด ๊ตฌ๋ ๋ฉ์๋๋ ์๋ฌ ๋๋ ์๋ฃ ์ํ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๊ฐ์ฒด map์ผ๋ก ์ ๊ณต๋๊ธฐ๋ ํฉ๋๋ค. ๋จ์ ํจ์ ํํ๋ณด๋ค ์์ฃผ ์ฌ์ฉํ์ง ์๊ฒ ์ง๋ง, ํ์ํ ๊ฒฝ์ฐ๋ฅผ ์ํด ์์๋๋ ๊ฒ์ด ์ข์ต๋๋ค.
// ํจ์ ๋์ ์, next, error, complete ๋ฉ์๋๊ฐ ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
const subscription = myObservable.subscribe({
// ์ฑ๊ณต์ ์ผ๋ก ๋ฐฉ์ถ๋์์ ๋
next: event => console.log(event),
// ์๋ฌ
error: error => console.log(error),
// ์๋ฃ ์ ํ ๋ฒ ํธ์ถ
complete: () => console.log('complete!')
});
์ค์ํ ๊ฒ์, ๊ตฌ๋
์ ๊ฐ๊ฐ ์๋ก์ด ์คํ ์ปจํ
์คํธ๋ฅผ ์์ฑํ๋ค๋ ๊ฒ์
๋๋ค. ์ด ๋ง์, subscribe
๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค ์๋ก์ด ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ์์ฑ๋๋ค๋ ๊ฒ์ด์ฃ .
// addEventListener ํธ์ถ
const subscription = myObservable.subscribe(event => console.log(event));
// addEventListener ๋ ํธ์ถ!
const secondSubscription = myObservable.subscribe(event => console.log(event));
// unsubscribe(๊ตฌ๋
ํด์ )๋ก ์ ๋ฆฌ
subscription.unsubscribe();
secondSubscription.unsubscribe();
๊ธฐ๋ณธ์ ์ผ๋ก, ๊ตฌ๋
์ ์ต์ ๋ฒ๋ธ๊ณผ ์ต์ ๋ฒ ์ฌ์ด์์ ์ผ๋์ผ, ์ผ๋ฐฉ์ ์ํต์ ์์ฑํฉ๋๋ค. ๋์ PR์ mergeํ ์ฌ๋ฌ๋ถ(:์ต์ ๋ฒ
)์๊ฒ ์ฌ์๋(:์ต์ ๋ฒ๋ธ
)์ด ์๋ฆฌ์ง๋ฅด๋ ๊ฒ(:๋ฐฉ์ถ
)์ฒ๋ผ์! ์ด๊ฒ์ Unicasting(์ ๋์บ์คํ
) ์ด๋ผ๊ณ ๋ ํฉ๋๋ค. ์ฌ๋ฌ๋ถ์ด ์ปจํผ๋ฐ์ค ๋ฐํ ์๋๋ฆฌ์ค(:ํ๋์ ์ต์ ๋ฒ๋ธ, ๋ง์ ์ต์ ๋ฒ
)๋ฅผ ๋ ์ ํธํ๋ค๋ฉด, Subject
๋ฅผ ์ด์ฉํ Multicasting(๋ฉํฐ์บ์คํ
) ์ ๊ทผ ๋ฐฉ์์ ์ทจํ๊ฒ ๋ฉ๋๋ค. ๋ค์์ ๋ฌธ์์์ ๋ ์์ธํ ์์๋ณด์ธ์!
์ต์ ๋ฒ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ณด๋ด๋ ์ต์ ๋ฒ๋ธ์ ๋ํด ์ค๋ช ํ ๋, push ๊ธฐ๋ฐ์ ๋ชจ๋ธ์ด๋ผ๋ ์ ์ ์ ์ํด์ผ ํฉ๋๋ค. ์์ค๋ ๊ตฌ๋ ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์์ง๋, ์ ๊ฒฝ์ฐ์ง๋ ์๊ณ ๋จ์ํ ๋ฐ์ดํฐ๋ฅผ ์๋๋ก ๋ฐ์ด๋ด๊ธฐ๋ง ํฉ๋๋ค.
RxJS๋ ์ด๋ฒคํธ ์คํธ๋ฆผ ์์์ ์๋ํ๋ ๊ฒ๋ ์ข์ง๋ง, ๊ทธ ์์ฒด๋ก๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. RxJS๊ฐ ์ด๋ฒคํธ์ฉ loadsh๋ผ๊ณ ๋ถ๋ฆฌ๊ฒ ๋ ์ด์ ๋ RxJS์...
Operators(์ฐ์ฐ์)
์ฐ์ฐ์๋ ๊ฐ์ ๋ณํํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ฌ, ๋ณํ๋ ๊ฐ๋ค์ ์ต์ ๋ฒ๋ธ์ ๋ฐํํฉ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ Array
๋ฉ์๋๋ฅผ ์ฌ์ฉํด๋ณธ ์ ์ด ์๋ค๋ฉด ๋๋ถ๋ถ์ RxJS ์ฐ์ฐ์๋ค์ด ์ต์ํ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด ์ต์ ๋ฒ๋ธ๋ก๋ถํฐ ๋ฐฉ์ถ๋ ๊ฐ๋ค์ ๋ณํํ๊ณ ์ถ์ ๋, map
์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
/*
* 'of'๋ ๊ฐ์ ์์๋๋ก ์ ๋ฌํฉ๋๋ค.
* ์ด ์์ ์์๋, 1,2,3,4,5๋ฅผ ์์๋๋ก ๋ด๋ณด๋
๋๋ค.
*/
const dataSource = of(1, 2, 3, 4, 5);
// ์์ค ์ต์ ๋ฒ๋ธ ๊ตฌ๋
const subscription = dataSource
.pipe(
// ๋ฐฉ์ถ๋ ๊ฐ์ ๊ฐ๊ฐ 1์ ๋ํ๊ธฐ
map(value => value + 1)
)
// ๋ก๊ทธ: 2, 3, 4, 5, 6
.subscribe(value => console.log(value));
๋๋ ํน์ ํ ๊ฐ์ ๊ฑธ๋ฌ๋ด๊ณ ์ถ์ ๋, filter
๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
import { of } from 'rxjs';
import { filter } from 'rxjs/operators';
const dataSource = of(1, 2, 3, 4, 5);
// ์์ค ์ต์ ๋ฒ๋ธ ๊ตฌ๋
const subscription = dataSource
.pipe(
// 2๋ณด๋ค ๊ฐ๊ฑฐ๋ ํฐ ๊ฐ๋ง ํ์ฉ
filter(value => value >= 2)
)
// ๋ก๊ทธ: 2, 3, 4, 5
.subscribe(value => console.log(value));
์ค๋ฌด์์ ํด๊ฒฐํด์ผ ํ ๋ฌธ์ ๊ฐ ์๋ค๋ฉด ๊ทธ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ์ฐ์ฐ์๊ฐ ์ด๋ฏธ ์กด์ฌ ํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. RxJS ์ฌ์ ์ ์์ํ๋ฉด ์์ฒญ๋ ์ซ์์ ์ฐ์ฐ์๋ค์ ์๋๋นํ ์ ์์ต๋๋ค. ํ์ง๋ง ํจ๊ณผ์ ์ธ ์์์ ์ํด ๋ช๋ช ์ฐ์ฐ์๋ค๋ง ๋จผ์ ์ตํ๋ ๋์ฃ . ์ธ์ ๊ฐ ๋ถ๊ฐํผํ๊ณ ์ด๋ ค์ด ๋ฌธ์ ๋ค์ด ๋ฐ์ํ๊ฒ ๋๋ฉด, ์ฐ์ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์ฐ์ฑ์ ์นญ์ฐฌํ๊ฒ ๋ ๊ฒ์ ๋๋ค.
๋์น์ฑ์ จ๋์? ์์ ์์ ์์ ์ฐ์ฐ์๋ '์ด๊ฒ' ์์ ์กด์ฌํ๋๋ฐ์....
Pipe
pipe
ํจ์๋ ์ต์ ๋ฒ๋ธ ๋ฐ์ดํฐ ์์ค์์ ์ฐ์ฐ์๊น์ง ์ด์ด์ง ์ฐ๊ฒฐ ๋ผ์ธ์
๋๋ค. ๊ณต์ฅ์ ์์์ฌ๊ฐ ์์ ํ์ด ๋๊ธฐ ์ , ์ผ๋ จ์ ๊ณผ์ ์ ๊ฑฐ์น๋ ๊ฒ์ฒ๋ผ ์์ค ๋ฐ์ดํฐ๋ ์ํฉ์ ๋ง๊ฒ ๋ฐ์ดํฐ๋ฅผ ์กฐ์, ํํฐ๋ง, ๊ทธ๋ฆฌ๊ณ ๋ณํํ ์ ์๋ ํ์ดํ๋ผ์ธ์ ํต๊ณผํฉ๋๋ค. pipe
๋ฅผ ํฌํจํ๋ ์ต์ ๋ฒ๋ธ ์ฒด์ธ ๋ด์์ 5๊ฐ ์ด์์ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ ๊ฑด, ๋๋ฌผ์ง ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ์ต์ ๋ฒ๋ธ๋ก ๊ตฌํ๋ ์๋ ์์ฑ ์๋ฃจ์ ์ ์์ฒญ ๋ฐ ํ์ ํ๋ก์ธ์ค ๋ชจ๋ ์ฐ์ฐ์๋ค์ ์ด์ฉํด ์ต์ ํํ ์ ์์ต๋๋ค.
// ํ
์คํธ ๋ฐ์ค์ ๊ฐ์ผ๋ก๋ถํฐ ์์ฑ๋ ์ต์ ๋ฒ๋ธ๊ณผ pipe ์ฒด์ธ ์ฐ์ฐ์๋ค
inputValue
.pipe(
// 200ms ๊ธฐ๋ค๋ฆฌ๊ธฐ
debounceTime(200),
// ์ฐ์ํด์ ๊ฐ์ ๊ฐ์ด ์จ๋ค๋ฉด, ๋ฌด์ํ๊ธฐ
distinctUntilChanged(),
// ์์ฒญ์ด ํ์ฑํ๋์ด์๋ ๋์ ๊ฐ์ด ์
๋ฐ์ดํธ๋๋ฉด ์ด์ ์์ฒญ์ ์ทจ์ํ๊ณ ์๋ก์ด ์ต์ ๋ฒ๋ธ๋ก 'switch(์ ํ)'ํฉ๋๋ค.
switchMap(searchTerm => typeaheadApi.search(searchTerm))
)
// ๊ตฌ๋
์์ฑ
.subscribe(results => {
// DOM ์
๋ฐ์ดํธ
});
๊ทธ๋ ์ง๋ง ์ํฉ์ ์ ์ ํ ์ฐ์ฐ์๊ฐ ๋ฌด์์ธ์ง ์ด๋ป๊ฒ ์ ์ ์์๊น์? ์ข์ ์์ ํ๋ ์๋ ค๋๋ฆฌ์๋ฉด...
์ฐ์ฐ์๋ ๊ณตํต๋ ์นดํ
๊ณ ๋ฆฌ๋ก ๋ฌถ์ ์ ์์ต๋๋ค
์ ์ ํ ์ฐ์ฐ์๋ฅผ ์ฐพ๊ธฐ ์ํด ๊ฐ์ฅ ๋จผ์ ํด์ผ ํ ์ผ์ ๊ด๋ จ๋ ์นดํ
๊ณ ๋ฆฌ๋ฅผ ์ฐพ๋ ๊ฒ์
๋๋ค. ์์ค๋ก๋ถํฐ ํํฐ๋ง๋ ๋ฐ์ดํฐ๊ฐ ํ์ํ๊ฐ์? ๊ทธ๋ฌ๋ฉด filtering
์ฐ์ฐ์๋ค์ ํ์ธํด๋ณด์ธ์. ์ต์ ๋ฒ๋ธ ์คํธ๋ฆผ์ ํต๊ณผํ๋ ๋ฐ์ดํฐ์ ํ๋ฆ ์ ๋ฒ๊ทธ๋ฅผ ์ถ์ ํ๊ณ ๋๋ฒ๊น
ํ๋ ค๊ณ ํ์๋์? ์์
์ ์ํํด์ค utility
์ฐ์ฐ์๋ค์ด ์์ต๋๋ค. ์ฐ์ฐ์ ์นดํ
๊ณ ๋ฆฌ์๋...
์ด ์ฐ์ฐ์๋ค์ ๊ฑฐ์ ๋ชจ๋ ๊ฒ๋ค๋ก๋ถํฐ ์ต์ ๋ฒ๋ธ์ ์์ฑํ๊ฒ๋ ํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ํฉ์ด๋ , ํน๋ณํ ์ํฉ์ด๋ ์ง ๊ฐ์ ์์ ๋กญ๊ฒ ์คํธ๋ฆผ์ผ๋ก ์ ํํ์ฃ .
์๋ฅผ ๋ค์ด, ์ ์ ์ ์คํฌ๋กค์ ๋ฐ๋ผ ์์ง์ด๋ Progress(์งํ๋ฅ ) ๋ฐ๋ฅผ ์์ฑํ๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค. ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ fromEvent
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด ์คํฌ๋กค ์ด๋ฒคํธ๋ฅผ ์คํธ๋ฆผ์ผ๋ก ์ ํํ ์ ์์ฃ .
fromEvent(scrollContainerElement, 'scroll')
.pipe(
// ๋ค์ ๋ฌธ์์์ ์ด ์ฝ๋์ ๋ํด ๋ ์์ธํ ๋ค๋ค๋ณผ ๊ฒ์
๋๋ค.
takeUntil(userLeavesArticle)
)
.subscribe(event => {
// ๊ณ์ฐํ๊ณ , DOM์ ์
๋ฐ์ดํธํ๊ธฐ
});
๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ ์์ฑ ์ฐ์ฐ์๋ค์ of
, from
, ๊ทธ๋ฆฌ๊ณ fromEvent
์
๋๋ค.
์ด ์ฐ์ฐ์๋ค์ ์ฌ๋ฌ ๊ฐ์ ์ต์ ๋ฒ๋ธ๋ค๋ก๋ถํฐ ์ ๋ณด๋ฅผ ๊ฒฐํฉํฉ๋๋ค. ์ฐ์ฐ์๋ค ๊ฐ์ ์ฐจ์ด๋ ๋ฐฉ์ถ๋ ๊ฐ์ ์์, ์๊ฐ, ๊ตฌ์กฐ์์ ์ฃผ๋ก ๋ํ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์ฌ๋ฌ ๊ฐ์ ๋ฐ์ดํฐ ์์ค์์ ์ ๋ฐ์ดํธ๋ ๊ฐ๋ค์ ๊ฒฐํฉํด ๊ณ์ฐ์ ์ํํ ์ ์์ต๋๋ค.
// ์์ค ์ค ํ๋๊ฐ ๋ฐฉ์ถํผ ๋๋ง๋ค, ๊ฐ ์์ค์์ ๋ง์ง๋ง์ผ๋ก ๋ฐฉ์ถ๋ ๊ฐ์ ์ ๊ณตํฉ๋๋ค.
combineLatest(sourceOne, sourceTwo).subscribe(
([latestValueFromSourceOne, latestValueFromSourceTwo]) => {
// ๊ณ์ฐ ์ํ
}
);
๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ ์กฐํฉ ์ฐ์ฐ์๋ค์ combineLatest
, concat
, merge
, startWith
, ๊ทธ๋ฆฌ๊ณ withLatestFrom
์
๋๋ค.
์ด ์ฐ์ฐ์๋ค์ ์ค๋ฅ๋ฅผ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌํ๊ณ , ์ค๋ฅ ๋ฐ์ ์์ ์ฌ์๋ํ๋ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์คํจํ ๋คํธ์ํฌ ์์ฒญ์ผ๋ก๋ถํฐ ๋ณดํธํ๊ธฐ ์ํด catchError
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์์ฃ .
source
.pipe(
mergeMap(value => {
return makeRequest(value).pipe(
catchError(handleErrorByReturningObservable)
);
})
)
.subscribe(value => {
// take action
});
๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ ์๋ฌ ์ฒ๋ฆฌ ์ฐ์ฐ์๋ catchError
์
๋๋ค.
์ด ์ฐ์ฐ์๋ค์ ์ต์ ๋ฒ๋ธ ์์ค์์ ๊ฐ์ ํ์ฉํ๊ฑฐ๋ ๊ฑฐ๋ถํ๊ณ , ์คํธ๋ฆผ ๋ด๋ถ์ ์ถ์ ๋ ๊ฐ์ ์ฒ๋ฆฌํ๋ ๊ธฐ์ ๋ค์ ์ ๊ณตํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์์ค์์ ์ฒ์ ๋ฐฉ์ถ๋ 5
๊ฐ์ ๊ฐ๋ง ๊ฐ๊ธฐ ์ํดtake
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
source.pipe(take(5)).subscribe(value => {
// ์ด๋ค ํ๋
});
๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ ํํฐ๋ง ์ฐ์ฐ์๋ debounceTime
, distinctUntilChanged
, filter
, take
, ๊ทธ๋ฆฌ๊ณ takeUntil
์
๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก RxJS์์ ์ต์ ๋ฒ๋ธ์ "์ฐจ๊ฐ์ด" ์ต์ ๋ฒ๋ธ์ด๊ฑฐ๋ ์ ๋์บ์คํธ(ํ๋์ ๊ตฌ๋ ์๋น ํ๋์ ์์ค)์ ํด๋นํฉ๋๋ค. ์ด ์ฐ์ฐ์๋ค์ ์ต์ ๋ฒ๋ธ์ "๋จ๊ฒ๊ฒ" ๋ง๋ค๊ฑฐ๋ ๋ฉํฐ์บ์คํธ๋ก ๋ง๋ค์ด ์ฌ๋ฌ ๊ตฌ๋ ์ ๊ฐ์ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๊ณต์ ํ ์ ์์ฃ .
์๋ฅผ ๋ค์ด, ๋์ค์ ๊ตฌ๋ ํ ๊ตฌ๋ ์์ ํ์ฑ๋ ์์ค ๋ด์์ ๊ฐ์ฅ ๋ง์ง๋ง์ผ๋ก ๋ฐฉ์ถ๋ ๊ฐ์ ๊ณต์ ํ ์ ์์ต๋๋ค.
const source = data.pipe(shareReplay());
const firstSubscriber = source.subscribe(value => {
// ์ด๋ค ํ๋
});
// ์ ์ ๋ค...
// 'secondSubscriber'๋ ๊ตฌ๋
์ ๋ง์ง๋ง์ผ๋ก ๋ฐฉ์ถ๋ ๊ฐ์ ๊ฐ๊ฒ ๋๊ณ , 'firstSubscriber'์ ์คํ ์ปจํ์คํธ๋ฅผ ๊ณต์ ํฉ๋๋ค.
const secondSubscriber = source.subscribe(value => {
// ์ด๋ค ํ๋
});
๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ ๋ฉํฐ์บ์คํ
์ฐ์ฐ์๋ shareReplay
์
๋๋ค.
์ฐ์ฐ์ ์ฒด์ธ์ ํต๊ณผํ๋ฉฐ ๊ฐ์ ๋ณํ์ํค๋ ๊ฑด ํํ ์์ ์ด์ฃ . ์ด ์ฐ์ฐ์๋ค์ ์ฌ๋ฌ๋ถ์ด ์ ํ ๋๋ถ๋ถ์ ์ํฉ๋ค์ ๋ํด ๋ณํ ๊ธฐ์ ์ ์ ๊ณตํฉ๋๋ค.
Redux ์ ์ ์ฌํ๊ฒ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ํ ๊ฐ์ฒด๋ฅผ ์ถ์ ํ๋ ค๋ฉด,
source
.pipe(
scan((accumulatedState, currentState) => {
return { ...accumulatedState, ...currentState };
})
)
.subscribe();
๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ ๋ณํ ์ฐ์ฐ์๋ concatMap
, map
, mergeMap
, scan
, ๊ทธ๋ฆฌ๊ณ switchMap
์
๋๋ค.
๊ณตํต๋ ๋์์ ๊ฐ์ง ์ฐ์ฐ์๋ค
๊ฐ์ ์นดํ ๊ณ ๋ฆฌ ๋ด์ ์ฐ์ฐ์๋ค์ ๊ณตํต๋ ๋์์ ๊ณต์ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด ๊ณตํต๋ ๋์๋ค์ ์์์ฐจ๋ฆฌ๊ฒ ๋๋ฉด, ๋จธ๋ฆฟ์์ ๋๋ง์ ์ฐ์ฐ์ ํธ๋ฆฌ ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๋๋ถ๋ถ์ ์ฐ์ฐ์๋ ์ฌ๊ธฐ์ ํฌํจ๋์ฃ ...
Operators that flatten(ํํํ ๊ธฐ๋ฐ์ ์ฐ์ฐ์)
๋ค์ ์ค๋ช ํ์๋ฉด, ๋ด๋ถ ์ต์ ๋ฒ๋ธ์ ๊ตฌ๋ ์ ๊ด๋ฆฌํ๋ ์ฐ์ฐ์๋ก, ๊ฐ๋ค์ ํ๋์ ์ต์ ๋ฒ๋ธ ์์ค๋ก ๋ฐฉ์ถํฉ๋๋ค. ์ต์ ๋ฒ๋ธ์ด๋ promise ๊ธฐ๋ฐ์ API์์ HTTP ์์ฒญ์ ์ฒ๋ฆฌํ ๋, ํํํ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์์ฃ .
fromEvent(button, 'click')
.pipe(
mergeMap(value => {
// ์ด ๋ด๋ถ ๊ตฌ๋
์ mergeMap์ผ๋ก ๊ด๋ฆฌ๋๊ณ , ์ต์ ๋ฒ์ ์๋ต๋ ๊ฐ์ ๋ฐฉ์ถํฉ๋๋ค.
return makeHttpRequest(value);
})
)
.subscribe(response => {
// ์ด๋ค ํ๋
});
ํํํ ๊ธฐ๋ฐ์ ์ฐ์ฐ์๋ฅผ ๋์์ ๋ฐ๋ผ ์ธ๋ถ์ ์ผ๋ก ๋๋ ๋ณด์๋ฉด....
Operators that switch
(์ ํ ๊ธฐ๋ฐ์ ์ฐ์ฐ์)
switch
(์ ํ ๊ธฐ๋ฐ์ ์ฐ์ฐ์)์ ๋ฑ ์ค์์น์ฒ๋ผ, switch
๊ธฐ๋ฐ์ ์ฐ์ฐ์๋ค์ ์์ค์์ ํ์ฌ์ ์ต์ ๋ฒ๋ธ์ ๊บผ ๋ฒ๋ฆฌ๊ณ (:๊ตฌ๋
ํด์
) ์ ์ต์ ๋ฒ๋ธ์ ์ผ ๋ฐฉ์ถ๋๊ฒ ํฉ๋๋ค. ์ ํ ์ฐ์ฐ์๋ ํ ๋ฒ์ ๋ ์ด์์ ํ์ฑํ๋ ์ต์ ๋ฒ๋ธ์ ํ์๋ก ํ์ง ์์ ๋ ์ ์ฉํฉ๋๋ค.
inputValueChanges
// ์ด์ ์์ฒญ/์ต์ ๋ฒ๋ธ์ด ์ทจ์๋์ด ์ ๊ฐ์ด ์ ๋ฌ๋๋ ๊ฒฝ์ฐ ๋ง์ง๋ง์ ์ ๋ฌ๋ ์ ๊ฐ๋ง ์ค์ํฉ๋๋ค.
.pipe(
// ๋ฐ์ดํฐ๋ฅผ ์ํ GET ์์ฒญ
switchMap(requestObservable)
)
.subscribe();
์ ํ ๊ธฐ๋ฐ์ ์ฐ์ฐ์๋ค์ switchAll
, switchMap
, ๊ทธ๋ฆฌ๊ณ switchMapTo
๊ฐ ์์ต๋๋ค.
Operators that concat
(์ฐ๊ฒฐ ๊ธฐ๋ฐ์ ์ฐ์ฐ์)
concat
(์ฐ๊ฒฐ ๊ธฐ๋ฐ์ ์ฐ์ฐ์)ATM ๊ธฐ๊ณ ์์ ์ค์์, ๋ค์ ๊ฑฐ๋๋ ์ด์ ๊ฑฐ๋๊ฐ ์๋ฃ๋๊ธฐ ์ ๊น์ง ์์๋ ์ ์์ต๋๋ค. ์ด๋ฅผ ์ต์ ๋ฒ๋ธ ์ฉ์ด๋ก ๋งํ์๋ฉด, ์ด์ ๊ตฌ๋ ์ด ์๋ฃ๋์ด ํธ๋ฆฌ๊ฑฐ๋๋ ์์๋๋ก ํ ๋ฒ์ ํ๋์ ๊ตฌ๋ ๋ง ๋ฐ์ํ๋ค๋ ๊ฒ์ ๋๋ค. ์ฐ๊ฒฐ ์ฐ์ฐ์๋ค์ ์์ ๊ฐ์ด ์คํ ์์๊ฐ ์ค์ํ ์ํฉ์์ ์ ์ฉํ์ฃ .
concat(
firstObservable,
// 'firstObservable'์ด ์๋ฃ๋๋ฉด ์์
secondObservable,
// 'secondObservable'์ด ์๋ฃ๋๋ฉด ์์
thirdObservable
).subscribe(values => {
// ์ด๋ค ํ๋
});
์ฐ๊ฒฐ ๊ธฐ๋ฐ์ ์ฐ์ฐ์๋ค์ concat
, concatAll
, concatMap
, ๊ทธ๋ฆฌ๊ณ concatMapTo
๊ฐ ์์ต๋๋ค.
Operators that merge
(๋ณํฉ ๊ธฐ๋ฐ์ ์ฐ์ฐ์)
merge
(๋ณํฉ ๊ธฐ๋ฐ์ ์ฐ์ฐ์)๊ณ ์๋๋ก์ ์ฐจ์ ํฉ๋ฅ ๋๋ก์ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋ณํฉ ๊ธฐ๋ฐ์ ์ฐ์ฐ์๋ ํ ์ฐจ์ ์์ ํ๋ฅด๋ ์ฌ๋ฌ ํ์ฑํ๋ ์ต์ ๋ฒ๋ธ๋ค์ ์ ์ฐฉ์์ผ๋ก ์ง์ํฉ๋๋ค. ์ด ์ฐ์ฐ์๋ค์ ์ฌ๋ฌ ์์ค ์ค ํ๋์์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋, ์์ ์ ํธ๋ฆฌ๊ฑฐํ๋ ค๋ ์ํฉ์์ ์ ์ฉํฉ๋๋ค.
merge(firstObservable, secondObservable)
// ์ฒซ ๋ฒ์งธ ๋๋ ๋ ๋ฒ์งธ ์ต์ ๋ฒ๋ธ์ ๋ฐฉ์ถ ์
.pipe(mergeMap(saveActivity))
.subscribe();
๋ณํฉ ๊ธฐ๋ฐ์ ์ฐ์ฐ์๋ค์ merge
, mergeMap
, mergeMapTo
๊ทธ๋ฆฌ๊ณ mergeAll
์ด ์์ต๋๋ค.
์ฐ์ฐ์ ๊ฐ์ ๊ธฐํ ์ ์ฌ์ฑ
์ ์ฌํ ๋ชฉํ๋ฅผ ๊ฐ๊ณ ์์ง๋ง ํธ๋ฆฌ๊ฑฐ์ ๋ค์์ฑ์ ์ ๊ณตํ๋ ์ฐ์ฐ์๋ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ํน์ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๊ณ ๋์ ์ต์ ๋ฒ๋ธ์ ๊ตฌ๋ ์ทจ์ํ๊ธฐ ์ํด ์ด๋ฌํ ์ฐ์ฐ์๋ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
take
๋n
๊ฐ์ ๊ฐ๋ง์ ์ํ ๋ ์ฌ์ฉํฉ๋๋ค.takeLast
๋ ๋ค์์n
๊ฐ์ ๊ฐ๋ง์ ์ํ ๋ ์ฌ์ฉํฉ๋๋ค.takeWhile
์ ์ถฉ์กฑํด์ผ ํ ๊ฐ์ ์กฐ๊ฑด์ด ์์ ๋ ์ฌ์ฉํฉ๋๋ค.takeUntil
์ ๋ค๋ฅธ ์์ค๊ฐ ๋ฐฉ์ถ๋ ๋๊น์ง ํ์ฑํ ์ํ๋ฅผ ์ ์งํ ๋ ์ฌ์ฉํฉ๋๋ค.
์ฒ์์ RxJS์ ์ฐ์ฐ์ ์๊ฐ ์๋์ ์ผ๋ก ๋๊ปด์ง ์ ์์ง๋ง, ์ด๋ฌํ ๊ณตํต๋ ๋์๊ณผ ํจํด์ RxJS์ ํ์ต ๊ฒฉ์ฐจ๋ฅผ ๋น ๋ฅด๊ฒ ๋ฉ์ธ ์ ์์ต๋๋ค.
์ด๊ฒ์ผ๋ก ๋ฌด์์ ํ ์ ์์ฃ ?
์ต์ ๋ฒ๋ธ์ ํตํ push ๊ธฐ๋ฐ ํ๋ก๊ทธ๋๋ฐ์ ๋์ฑ ์ต์ํด์ง๋ฉด ์ต์ ๋ฒ๋ธ ์คํธ๋ฆผ์ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ ๋น๋๊ธฐ ๋์๋ค์ ๋ชจ๋ธ๋งํ ์ ์์ต๋๋ค. ํนํ ๋ณต์กํ ๋์์ ๋ํ ๊ฐ๋จํ ์๋ฃจ์ ๊ณผ ๋ค์์ฑ์ ์ ๊ณตํ์ฃ .
์๋ฅผ ๋ค์ด, ์ ์ ๊ฐ ํด์ฆ ์ง๋ฌธ์ ๋ตํ์ ๋ ์ ์ ์ ํ๋ ๋ด์ญ์ ์ ์ฅํ๋ ์์ฒญ์ ๋ณด๋ด๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค. ์ด๊ธฐ ๊ตฌํ์ ๊ฐ ์ด๋ฒคํธ์ ๋ํ ์ ์ฅ ์์ฒญ์ ์์ํ๋ mergeMap
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ์ฃ ?
const formEvents = fromEvent(formField, 'click');
const subscription = formEvents
.pipe(
map(convertToAppropriateValue),
mergeMap(saveRequest)
)
.subscribe();
์ดํ, ์ ์ฅ ์ ์์๋ฅผ ํ์ธํด์ผ ํ๋ค๊ณ ํ๋จ๋์์ ๋ ์ฐ์ฐ์ ๋์์ ๋ํ ์ง์์ด ์๋ค๋ฉด, ๋ณต์กํ ๋๊ธฐ์ด ์์คํ
์ ๊ตฌํํ๋ ๋์ ์ mergeMap
์ฐ์ฐ์๋ฅผ concatMap
์ผ๋ก ๊ต์ฒดํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
const formEvents = fromEvent(formField, 'click');
const subscription = formEvents
.pipe(
map(convertToAppropriateValue),
// ์ด์ ์ด์ ์์ฒญ์ด ์๋ฃ๋ ๋๊น์ง ๋ค์ ์์ฒญ์ ์์๋์ง ์์ต๋๋ค!
concatMap(saveRequest)
)
.subscribe();
๊ณ ์ ํ ๋จ์ด๋ฅผ ๋ฐ๊ฟ ์ด๋ฒคํธ ์์ฒญ์ ์์๋๋ก ์ฒ๋ฆฌํ๊ฒ ๋ง๋ ๊ฑด, ์์ผ๋ก ์ฐ๋ฆฌ๊ฐ ํ ์ ์๋ ์ผ์ ๋นํ๋ฉด ๋น์ฐ์ ์ผ๊ฐ์ ๋ถ๊ณผํ์ฃ !
๊ณ์ํ์ธ์!
RxJS๋ฅผ ๋ฐฐ์ฐ๋ ๊ฒ ๋๋ ค์ธ ์ ์์ง๋ง, ํฌ์ ๊ฐ์น๋ ์ถฉ๋ถํ๋ค๊ณ ์ฝ์๋๋ฆด ์ ์์ต๋๋ค. ์ค๋ช ๋๋ฆฐ ๊ฐ๋ ์ค ์ผ๋ถ๋ถ์ด ์ฌ์ ํ ๋ช ํํ์ง(๋๋ ์ดํด๋์ง) ์์๋, ๊ฑฑ์ ํ์ง ๋ง์ธ์! ๊ณง ๋ชจ๋ ๊ฒ ๋ช ํํด์ง ๊ฑฐ์์.
์ฌ์ดํธ ์ผ์ชฝ์ ์๋ ์ฐ์ฐ์๋ค์ ์์์, ์ ๋ฌธ์๋ฅผ ์ํ ์๋ฃ๋ค์ ํ์ธํด๋ณด์ธ์. ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ ์ ๋ฌธ๊ฐ๊ฐ ๋๊ธฐ ์ํ ์ฌ๋ฌ๋ถ๋ค์ ์ฌ์ ์ ์์ํฉ๋๋ค!
Last updated