Observable based state management Library. Action / Dispatch / On / Reducer + able
TC39 Observable์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋๋ค. RxJS์ Redux์์ ์๊ฐ์ ๋ฐ์ ์์ฑํ์์ต๋๋ค. ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชจ๋ ์์ฒญ ๊ฐ๋ ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ ํ์ต ์ง์ ์ฅ๋ฒฝ๊ณผ verboseํ ๋ฌธ๋ฒ์ผ๋ก ์ธํด ์ ๊ทผ์ฑ์ด ๋จ์ด์ง๋ ๋ถ๋ถ์ ๋ณด๊ฐํ๊ณ ๊ฐ๊ฐ์ ์ฅ์ ๋ง์ ๊ฒฐํฉํ ์ ์๋๋ก ํ์์ต๋๋ค.
https://github.com/tc39/proposal-observable
https://rxjs-dev.firebaseapp.com/guide/overview
์น ์๋น์ค๊ฐ ๊ฑฐ๋ํด ์ง ์๋ก ํ๋ก ํธ์ํธ๋ ๋ณต์ก์ฑ์ด๋ผ๋ ๋ฌธ์ ๋ฅผ ๋ง์ด ํ๊ฒ ๋ฉ๋๋ค. DOM API์ด๋ผ๋ ๋ฌธ์ ๋ 10๋ ์ด ๋๋๋ก ์ ๋ฐ์ ํด์จ React, Vue, Angular, Svelte์ ๊ฐ์ ์น ํ๋ ์์ํฌ๋ผ๋ ๋๊ตฌ๋ก ์ฝ๊ฒ ์ ์ด๊ฐ ๊ฐ๋ฅํด์ง ์ค๋๋ ์๋ ์ํ๊ด๋ฆฌ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ผ๋ ์ฅ๋ฒฝ์ ๋จ์ ์์ต๋๋ค.
Redux์ RxJs๋ ํ์ฌ ์ ์ ์จ์ ์์ด ๊ฐ๊ณ ์๋ ์ํฉ์ด์ง๋ง ๊ทธ ๋ฌธ์ ์ธ์๊ณผ ํด๋ฒ์ ์ฌ์ ํ ํ๋ฅญํ ํด๊ฒฐ์ฑ ์ด๋ฉฐ ๋ค์ ์์ฌ์ด ๋ฌธ๋ฒ๊ณผ ์ง์ ์ฅ๋ฒฝ์ ์ต์ํ ํ ์ ์๋๋ก API๋ฅผ ์ต๋ํ ๊ฐ์ํ๊ฒ ์ฌ์ค๊ณ ํ์์ต๋๋ค.
ํ์ฌ๋ XState์ ๊ฐ์ ์ ํ ์ํ๊ธฐ๊ณ๋ Recoil๋ฑ์ family๋ฑ์ ์ต์ ํจ๋ฌ๋ค์๊น์ง ํก์ํด 1) ์ํ๊ด๋ฆฌ 2) ๋น๋๊ธฐ 3) ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ 4) ์ํ๋จธ์ ์ด๋ผ๋ ์๋ก์ด ํ๋๋ฃ์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ํจํค์ง ํด ๋๊ฐ ์์ ์ ๋๋ค.
- Rxjs: Pipe method vs DotChain vs Pipeline operator (TBD)
- Redux: Why Reducer? Why Redux is verbose? What is benefit using Redux?
- Props Drill, Context API
- ํ๋ก ํธ ์๋์์ ์ํ๊ด๋ฆฌ๋ ๋ฌด์์ด๋ฉฐ ์ ํ์ํ ๊น?
- ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ด๋?
Write less, Do More!
// store.ts
const _INCREARE = action("_INCREARE")
const _DECREARE = action("_DECREARE")
const _RESET = action("_RESET")
export const counter$ = reducer(0, "counter$", counter$ => {
on(_INCREARE)
.writeTo(counter$, () => count => count + 1)
on(_DECREARE)
.writeTo(counter$, () => count => count - 1)
on(_RESET)
.writeTo(counter$, 0)
})
<script>
import {dispatch} from "adorable"
import {_INCREARE, _DECREARE, _RESET} from "./store"
import {counter$} from "./store"
const inc = () => dispatch(_INCREARE())
const dec = () => dispatch(_DECREARE())
const reset = () => dispatch(_RESET())
</script>
<div>count: {$counter$}</div>
<button on:click={inc}>inc</button>
<button on:click={dec}>dec</button>
<button on:click={reset}>reset</button>
const _INCREARE = action("_INCREARE")
const _DECREARE = action("_DECREARE")
const on_inc_click = () => dispatch(_INCREARE())
const on_dec_click = () => dispatch(_DECREARE())
on(_INCREARE)
.map(...)
.filter(...)
.writeTo()
on(_DECREARE)
.map(...)
.filter(...)
.writeTo()
const counter$ = reducer(0, "counter$", counter$ => {
on(_INCREARE)
.writeTo(counter$, () => count => count + 1)
on(_DECREARE)
.writeTo(counter$, () => count => count - 1)
})
const ref$ = ref(0)
ref$.set(10)
ref$.update(value => value + 1)
on(_INCREARE)
.tap(value => console.log("INCREASE!", value))
.createEffect()
story("counter log", () => {
on(_INCREARE)
.tap(value => console.log("INCREASE!", value))
.createEffect()
...
})
database(`/foo/bar`)
.tap(value => { ... })
.createEffect()
const nestedValue$ = database(`/foo/bar/baz`)
nestedValue$.set(100)
nestedValue$.update(baz => baz + 100)
const nestedValueArray$ = database(`/foo/bar/collection`).orderBy((a, b) => a.timestamp - b.timestamp)
const nestedValue$ = SELECT(db.foo.bar)
UPDATE(db.foo.bar).set(100)
UPDATE(db.foo.bar).update(bar => bar + 100)
DELETE(db.foo.bar)
const nestedValueArray$ = SELECT(db.foo.bar.collection).ORDER_BY((a, b) => a.timestamp - b.timestamp)
const todo = {
id: 1,
title: "hello"
}
INSERT(db.foo.bar.collection, "id").VALUES(todo)
- ์๋ฒ API์ฐ๋์ ์ด๋ป๊ฒ loading๊ณผ ์บ์์ invalidate๋ฅผ ๊ด๋ฆฌํ ๊ฒ์ธ๊ฐ?
testCase("test for counter", ({given, when, then}) => {
given(streamA$, 10)
given(streamB$, "abc")
given(streamC$, "def")
when(_ACTION_A("abcdef"))
then(() => {
on(_ACTION_A.REQUEST)
.exptectTo("abcdef")
on(_ACTION_A.SUCCESS)
.exptectTo(300)
on(_ACTION_A.FAILTURE)
.exptectTo(300)
})
})
- ๊ฐ๋ฐ ํธ์๋ฅผ ์ํด์ Rxjs์ pipe method๋ฅผ ๋ค์ dot chain method๋ก ๋ง๋ค๊ณ , ์ค์ ์์ ๊ผญ ์ฐ์ด๋ operator๋ง์ ๊ณจ๋ผ ๋จ์ํํ๊ณ typescript๋ฅผ ๋ถ์์ต๋๋ค.
- toPromise
- castAsync
- combineLatest
- concat
- defer
- EMPTY
- forkjoin
- fromEvent
- fromEventPattern
- fromPromise
- merge
- NEVER
- timer
- throwError
- bufferCount
- bufferTime
- concat
- count
- concatMap
- debounce
- debounceTime
- delay
- distinctUntilChanged
- duration
- exhaustMap
- filter
- finalize
- ignoreElements
- initialize
- last
- map
- mapTo
- mergeAll
- mergeMap
- scan
- share
- shareReplay
- skip
- skipUntil
- startWith
- switchMap
- tap
- take
- takeLast
- takeUntil
- takeWhile
- throttle
- throttleTime
- timeout
- trace
- until
- waitFor
- withLatestFrom