redux-saga
๋ ๋น๋๊ธฐ(=์ฌ์ด๋ ์ดํํธ)์ ์ต์ ํ๋ฅผ ์ํ ๋ฏธ๋ค์จ์ด ์ด๋ค.redux-saga
๋ ์ก์
์ ๋ชจ๋ํฐ๋งํ๋ค๊ฐ, ํน์ ์ก์
์ด ๋ฐ์ํ๋ฉด ํน์ ์์
(์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋ ์คํ, ๋ค๋ฅธ ์ก์
๋์คํจ์น, ์ํ ์กฐํ ๋ฑ)์ ํ๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ๋๋ค.๐ช ์ ๋๋ ์ดํฐ
Saga๋ ์ ๋๋ ์ดํฐ๋ฅผ ์ด์ฉํ์ฌ ๋ชจ๋ ๊ฒ์ ์ํํ๋ค. ์ ๋๋ ์ดํฐ ๋ฌธ๋ฒ์ ์๋ฐ์คํฌ๋ฆฝํธ ES6์ ํฌํจ๋ ๋ฌธ๋ฒ์ด๋ค.next()
๋ฅผ ํธ์ถํ๋ฉด {value์ done ํ๋กํผํฐ}๊ฐ ํฌํจ๋ Result๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.// generator ๋ฌธ๋ฒ function* thisIsGenerator() { console.log('First Call'); yield 'First'; console.log('Second Call'); yield 'Second'; console.log('Third Call'); } const thisIsGeneratorObject = thisIsGenerator(); // next()๋ก ํธ์ถํ์ฌ ์ ๋๋ ์ดํฐ๊ฐ์ฒด ๋ฐํ( { value:__, done:__ } ) thisIsGeneratorObject.next(); // First Call { value: 'First', done: false } thisIsGeneratorObject.next(); // Second Call { value: 'Second', done: false } thisIsGeneratorObject.next(); // Third Call { value: 'Undefined', done: true }
โ ์ผ๋ฐ ํจ์์ ๋ค๋ฅธ ์ ์, ์ฝ๋ ๋ธ๋ก์ด ํ ๋ฒ์ ์คํ๋์ง ์๋๋ค.
์ฒ์ next()๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ์ฒซ ๋ฒ์งธ yield๊น์ง ํธ์ถ๋๊ณ ์ผ์ ์ค์ง ๋๋ค.
๋ ๋ฒ์งธ next()๋ฉ์๋๋ฅผ ํธ์ถํด์ผ ๋ ๋ฒ์งธ yield๊น์ง ํธ์ถ๋๊ณ ๋ ์ผ์ ์ค์ง ๋๋ค.
๋ง์ง๋ง์ผ๋ก next()๋ฉ์๋๋ฅผ ํธ์ถํด์ผ๋ง, Result๊ฐ์ฒด์ done ํ๋กํผํฐ ๊ฐ์ด true๊ฐ ๋๋ค.โ generator ํจ์๋ฅผ ๋ง๋ค ๋๋
function*
ํค์๋๋ฅผ ์ฌ์ฉํ๋ค.
const generator = generatorFunction()
๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค. generator ํจ์๋ฅผ ํธ์ถํ๋ค๊ณ ํด์ ํด๋น ํจ์์ ์ฝ๋๊ฐ ๋ฐ๋ก ์์๋์ง๋ ์๋๋ค.generator.next()
๋ฅผ ํธ์ถํด์ผ ์ฝ๋๊ฐ ์คํ๋๊ณ yield๋ฅผ ํ ๊ฐ์ ๋ฐํํ๊ณ ์ฝ๋ ํ๋ฆ์ ๋ฉ์ถ๋ค. ๋๋ค์generator.next()
๋ฅผ ํด์ผ ์ด์ด์ง๋ค.๐ช ์ดํํธ
์ดํํธ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ๋ด์ฉ์ ๋ด๊ณ ์๋ค. ์ฌ๊ฐ๋ฅผ ์คํํ๋ ์คํ๋ถ์๊ฒ ์ด๋ ํ ๋์์ ์ํํด์ผ ํ ์ง ์๋ ค์ฃผ๋ ์ผ๋ฐ ๊ฐ์ฒด(Plain Object)์ด๋ค.
Redux-Saga์์๋ ์ด๋ฌํ ์ดํํธ ๋ค์yield
๋ฅผ ์ด์ฉํ์ฌ ํธ์ถํ๊ณ ์ํ๋ ๋ด์ฉ์ ๋ค์ ๋๋ ค ๋ฐ์ ๊ทธ ๋ค์ ์ก์ ๋ค์ ์ํํ๋ค. ๊ฒฐ๊ตญ Redux-Saga๋ ์ ๋๋ ์ดํฐ๋ฅผ ํตํด ์ดํํธ๋ฅผ ์ํํ๋ ์ญํ ์ ํ๋ค๊ณ ๋ณผ ์ ์๋ค.
์ผ๋ฐ์ ์ผ๋กput()
,call()
,select()
๋ฑ์ ํฌํผ ํจ์๋ฅผ ํธ์ถํจ์ผ๋ก์จ ํด๋น ์ดํํธ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
๋ํ์ ์ธ ๊ฒ๋ค๋ก๋take
,call
,put
๋ฑ์ด ์๋ค.
๋ฆฌ๋์ค ์ฌ๊ฐ๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ ๋๋ ์ดํฐ ๋ฌธ๋ฒ์ ์ด์ฉํ๋ค(์ฌ๊ฐ = ์ ๋๋ ์ดํฐ๋ฅผ ๋ฐํํ๋ ํจ์).
function
ํํ์ ํน์ํ ํจ์๋ก ์์ฑ๋ ์ ๋๋ ์ดํฐ ๊ฐ์ฒด๋ { value, done } ์์ฑ์ ๊ฐ์ง๊ณ ์๋ ์ ๋ง ํน์ํ ๊ฐ์ฒด๋ค.
์ ๋๋ ์ดํฐ ํจ์ ๋ด๋ถ์์ yield
๋ผ๊ณ ํ๋ ํค์๋๋ก ๋ค์ ๊ฐ, ๋์์ ์ ์ดํ๋ค(์ฌ๊ฐ๋ yield ํํ์์ ๋ง๋ ๋๋ง๋ค ์คํ์ด ์ค๋จ).
๊ทธ๋์ while(true)์ ๊ฐ์ ๋ฌดํ๋ฃจํ๋ ์ ๋๋ ์ดํฐ ํจ์ ๋ด๋ถ์์ ์ฌ์ฉํ ์ ์๋ค. yield ํค์๋๋ฅผ ๋ง๋๋ฉด ๋ค์ ๋ก์ง์ด๋ ๊ฐ์ ์ ๋ฌํ๊ณ ์ฐ์ ํจ์์์ ๋ฒ์ด๋๊ธฐ ๋๋ฌธ์ด๋ค.
โ .next()
๋ผ๊ณ ํ๋ ๋ฉ์๋๋ฅผ ๋ฐ์์ ๋๋ง ๋ค์ ๋์์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋น๋๊ธฐ์ ์ธ ์ฒ๋ฆฌ๋ฅผ ์ ์ดํ๊ธฐ ์ข๋ค. (next()
ํจ์๋ฅผ ํธ์ถํจ์ผ๋ก์จ ์ฌ๊ฐ๋ฅผ ์คํํ ์ ์๋ค. next()
ํจ์์ ์ธ์๋ก ๋๊ธฐ๋ ๊ฐ์ ํด๋น ์ฌ๊ฐ์ ์คํ์ด ์ค๋จ๋์ด ์๋ ์์น์ yield ํํ์ ์๋ฆฌ๋ฅผ ์ฑ์์ค๋ค)
๋ฆฌ๋์ค ์ฌ๊ฐ๊ฐ ์ ๋๋ ์ดํฐ ๋ฌธ๋ฒ ๊ธฐ๋ฐ์ธ ๊ฒ๋ ๋น๋๊ธฐ์ ์ฒ๋ฆฌ์ ์ธ์๊ณผ ์ ์ด๋ฅผ ์ ํต์ ํ๊ธฐ ์ํจ์ด๋ค. ๋ฆฌ๋์์ ์ ์๋ ํน์ ํ ์ก์ ์ ๊ธฐ๋ค๋ฆฌ๋ค๊ฐ ์ก์ ์ด ๋ฐ์ํ๋ ์์ ์์ yield์ ๋ฑ๋ก๋ ํจ์๋ ๋ก์ง์ด ๋์ํ๊ฒ ํ๋ ๊ฒ์ด๋ค. ์ด๋ฐ ์ฒ๋ฆฌ๋ค์ ๋ฆฌ๋์ค ์ฌ๊ฐ์ ๋ฏธ๋ฆฌ ์ ์๋ ์ฌ๋ฌ ๋ถ์ํจ๊ณผ(effects) ํจ์๋ค๋ก ๋์ํ๊ฒ ๋๋ค.
๐ ์คํ ์ด
๐ ๋ฏธ๋ค์จ์ด store
=> next
=> dispatch
๐ ์คํ ์ด ์ธํธ์ storeCreator
=> storeCreator
๐ ๋ฆฌ๋์ค ๋์ ์๋ฆฌ
store={store}
)npm i redux-saga
์ค์น ํ ๋ฏธ๋ค์จ์ด์ ์ง์ด๋ฃ๋๋ค.
// store.js ํ์ผ ์์ฑ
import { createStore, combineReducers, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import reducer from './reducer'; // reducer๊ฐ ์ ์๋ ํ์ผ import
import rootSaga from './saga'; // index.js์ rootSaga ํ์ผ import
// ์ฌ๋ฌ ์ํ๊ฐ์ ๋ณ๊ฒฝํ๋ ๋ฆฌ๋์๋ค์ ํ๋์ ๋ฆฌ๋์ ํจ์๋ก ํจ์น๋ค.
const rootReducer = combineReducers({ reducer });
// ๋ฆฌ๋์ค ์ฌ๊ฐ์์ createSagaMiddleware๋ฅผ ๋ถ๋ฌ์์, sagaMiddleware ๊ฐ์ฒด ์์ฑ
const sagaMiddleware = createSagaMiddleware();
// store ์์ฑ (sagaMiddleware ๊ฐ์ฒด ์ฐ๊ฒฐ โก applyMiddleware ํจ์์ ์ธ์๋ก ๋๊ฒจ์ฃผ๊ธฐ)
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
// ์ฌ๊ฐ ๋ฏธ๋ค์จ์ด์์ run ๋ฉ์๋์ "ํตํฉ ์ฌ๊ฐ ํจ์(rootSagaํจ์)"๋ฅผ ์ฐ๊ฒฐ/์คํ์ํจ๋ค.
sagaMiddleware.run(rootSaga);
export default store;
// app.js
import withReduxSaga from 'next-redux-saga';
(...)
export default Wrapper.withRedux(withReduxSaga(App));
// saga/index.js
import { all, fork } from 'redux-saga/effects'; // ๋ถ์ํจ๊ณผ ํจ์(all, fork)
import userSaga from './user';
// yield ํค์๋ ๋ค์ ๋ฆฌ๋์ค ์ฌ๊ฐ์ ๋ถ์ํจ๊ณผ ํจ์๊ฐ ์จ๋ค.
// rootSaga ์ ๋๋ ์ดํฐ ํจ์ ๋ด๋ถ์ ๋ฑ๋ก๋ yield ํค์๋์๋ all์ด๋ผ๊ณ ํ๋ ๋ถ์ํจ๊ณผ ํจ์๊ฐ ๋ถ๋๋ค.
// ๋ฑ๋ก๋ ํจ์๊ฐ ๋์์ ์คํ๋ ์ ์๋๋ก ์ฒ๋ฆฌํ๋ค. (rootSaga๋ฅผ ๋ง๋ค์ด์ ํ๋๋ก ํฉ์น๋ ์์
)
export default function* rootSaga() {
yield all([fork(userSaga)]);
}
// fork ๋ถ์ํจ๊ณผ ํจ์๋ ์ก์
์ ๋ฐ์์ํจ๋ค.
put
: dispatch์ saga๋ฒ์ ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค. Action
์ dispatch
ํ๋ค. ( = store.dispatch()
ํจ์)
all
: ๋ฐฐ์ด์ ๋ฐ์์, ๋ฐฐ์ด์ ๋ค์ด์๋ ๊ฒ๋ค์ ํ๋ฒ์ ์คํํ๋ค.
call
: ๋๊ธฐ์ ์ผ๋ก ํจ์๋ฅผ ํธ์ถํ๋ค.
fork
: ๋น๋๊ธฐ์ ์ผ๋ก ํจ์๋ฅผ ํธ์ถํ๋ค.