# * Redux thunk
๋ฆฌ๋์ค๋ฅผ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋น๋๊ธฐ ์์ ์ ์ํด์ ํน์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํด์ผํ๋ค. ์ด๋ redux-saga, mobX, redux thunk ๋ฑ ๋ง์ ๋ฏธ๋ค์จ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ์ด๋ค ๊ฒ๊ณผ ์ํคํ ์ณ๋ง์ ๊ตฌํํ๋์ ๋ฐ๋ผ ์ฌ์ฉํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ค๋ฅผ ๊ฒ ์ด๋ค.
Redux-thunk๋ ๊ทธ์ค์์๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋น๋๊ธฐ์์
์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด ์ด๋ค.
๋ฆฌ๋์ค๋ฅผ ๊ฐ๋ฐํ Dan Abramov
๊ฐ ๋ง๋ค์๊ณ , redux ๊ณต์ ๋งค๋ด์ผ : ๋น๋๊ธฐ ์ก์
์์ฑ์์์๋ Redux-thunk๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ ์์
์ ๋ค๋ฃฌ๋ค. ๊ทธ๋งํผ Redux-thunk๋ก ๋น๋๊ธฐ ์์
์ ๊ด๋ฆฌํ๋๊ฑด ๋งค์ฐ ์ง๊ด์ ์ด๊ณ ๊ฐ๋จํ๋ค.
# Thunk?
thunk๋ ์๋ธ๋ฃจํด(์ดํ 'ํจ์')์ ์ถ๊ฐ ๊ณ์ฐ์ ์ฃผ์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ํจ์์ด๋ค.
์์)
const wabi = '29' + 'years old'; // '29years old'
const wabi = () => '29' + 'years old';
wabi(); //'29years old'
2
3
์ ์ฝ๋์ ์๋ ์ฝ๋๊ฐ ๋ค๋ฅธ์ ์ ํจ์ํํ๋ก ๊ฐ์๋ค๋ ์ ์ด๋ค.
์ฆ, wabi() ๋ผ๊ณ ํจ์ ํธ์ถ
์ ํด์ผ ๊ฐ์ด ๋ฐํ๋๋ค.
# Redux-thunk์ ์ก์ ์์ฑ์ ์์
redux-thunk๋ ์ ์์์์ thunk ๊ฐ ๋ฌด์์ธ์ง ๋ณธ ๊ฒ ์ฒ๋ผ, ๋ฆฌ๋์ค์ ๊ฐ์ฒด๋ฅผ ๋ณด๋ด๊ธฐ๋ง ํ๋๊ฒ์ด ์๋, ํจ์๋ฅผ ์์ฑํ๋ ์ก์
์์ฑ์
๋ฅผ ๋ณด๋ผ ์ ์๊ฒ ํด์ฃผ๋ ๋ฏธ๋ค์จ์ด์ด๋ค.
์์) ์ผ๋ฐ์ ์ธ ์ก์ ์์ฑ์
const highlight = (flag) => ({
type:'HIGHLIGHT',
flag
})
const insertJSON = (json) => ({
type:'INSERTJSON',
json
})
const insertValue = (selKey,entryInfo,val,rerender) => ({
type:'INSERTVALUE',
selKey,entryInfo,val,rerender
})
2
3
4
5
6
7
8
9
10
11
12
13
14
์์์ ๋ณด๋ ๊ฒ ์ฒ๋ผ ์ผ๋ฐ์ ์ธ ์ก์
์์ฑ์
๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง๊ณ ์ก์
๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์์
๋ง ํ๋ค.
์ผ๋ฐ์ ์ธ ์ก์
์์ฑ์
๋ ๋น๋๊ธฐ์์
(= 1์ด๋ค ์คํ ๋๋ ํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์ํฉ์ ๋ฐ๋ผ ์์
์งํ ๋๋ ์ค์ง)
์ด ๋ถ๊ฐํ์ง๋ง, redux-thunk๋ ๊ฐ๋ฅํ๋ค.
์์ 1) ์ highlight ์ก์
์์ฑ์
1์ด ๋ค ์คํ ๋น๋๊ธฐ ์์
const highlight = (flag) => ({
type:'HIGHLIGHT',
flag
})
const highlightAsync = () => {
return dispatch => { // dispatch ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง ํจ์ ๋ฐํ
setTimeout(() => {
dispatch(highlight(true));
}, 1000);
}
}
//1์ด ๋ค ํ์ด๋ผ์ดํธ flag๊ฐ true๋ก ์ํ๊ฐ์ด ๋ณ๊ฒฝ๋๋ ํจ์๋ฅผ ๋ฐํํ๋ค.
2
3
4
5
6
7
8
9
10
11
12
store.dispatch(highlightAsync()); ๋ฅผ ํธ์ถํ๋ฉด ์ก์
ํ์
HIGHLIGHT
์ก์
์ด 1์ด๋ค ๋์คํจ์น๋๋ค.
์์ 2) flag๊ฐ ํ์ฌ ์ํ์ ๋ฐ๋๋ก ์ํ๋ณํ๋ฅผ ํ๊ฒ ๋ํ๋ธ๋ค. (1์ด ๋ค)
const highlight = (flag) => ({
type:'HIGHLIGHT',
flag
})
const highlightAsync = () => {
return (dispatch,getState) => { // dispatch, getState ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง ํจ์ ๋ฐํ
const { highlight } = getState();
setTimeout(() => {
dispatch(highlight(!highlight));
}, 1000);
}
}
2
3
4
5
6
7
8
9
10
11
12
์ ์์์์๋ getState ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด ํ์ฌ์ํ๊ฐ์ ํ์ธํ ํด๋น boolean๊ฐ์ ๋ฐ๋๋ก ์ํ๋ณํ๋ฅผ 1์ด ๋ค ์ผ์ผํค๋ ํจ์๋ฅผ ๋ฐํํ๋ค. ๋๋ dispatch๋ฅผ ํ๊ธฐ ์ซ์ ๊ฒฝ์ฐ, return ์ผ๋ก ์ํ๋ณํ๋ฅผ ์ค๋จ ํ ์๋ ์๋ค.
์์ 3) ์ํ๋ณํ ์ค๋จ
const highlight = (flag) => ({
type:'HIGHLIGHT',
flag
})
const highlightAsync = () => {
return (dispatch,getState) => { // dispatch, getState ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง ํจ์ ๋ฐํ
const { highlight } = getState();
if(!highlight) return;
//ํ์ด๋ผ์ดํธ๊ฐ false ์ผ ๊ฒฝ์ฐ, ์ค๋จ
setTimeout(() => {
dispatch(highlight(highlight));
}, 1000);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
์ ์์์ฒ๋ผ ํ์ฌ ์คํ ์ด ์ํ ๊ฐ์ ๋ฐ๋ผ์ ์ก์ dispatch๋ฅผ ์ค๋จ ์ํฌ ์๋ ์๋ค.
# Redux-thunk๋ฅผ ์ด์ฉํ ์น ์์ฒญ ์์
//์ก์
ํ์
์ ์
const API_REQUEST = "API_REQUEST";
const API_SUCCESS = "API_SUCCESS";
const API_FAILURE = "API_FAILURE";
//์ก์
์์ฑ์
const asyncRequest = () => ({
type: API_REQUEST
})
const asyncSuccess = (data) => ({
type:API_SUCCESS,
data
})
const asyncFailure = (error) => ({
type: API_FAILURE,
error
})
//์น ํต์ ์ก์
์์ฑ์ ๋ด๋ถ ๋ค์ด๊ฐ promise ๋ฐํ ํจ์ 'callAPI'
const callAPI = (data) => {
const promise = fetch({...data
//data ๋งค๊ฐ๋ณ์์ api ํต์ ์ ์ํ fetchํจ์์ ์ฌ์ฉ๋ ๋ณ์ ์ฝ์
.
});
return promise.then(response => response.json())
}
//์น ํต์ ์ก์
const dispatchAsyncAct = data => (dispatch,getState) =>{
dispatch(asyncRequest);
callAPI(data)
.then(json => dispatch(asyncSuccess(json))
.catch(error => dispatch(asyncFailure(error))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
์ ์์์ฝ๋ ์น ํต์ ๋ก์ง์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฆฌ๋์ค ๊ตฌ์กฐ๋ ์ฝ๋ํจํด์ด ๊ฐ๋ฐ์๋ง๋ค, ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ ์ฝ๋๋ฅผ ๋ณด๊ณ ์์ ์ ํ๋ก์ ํธ์ ์๋ง๊ฒ ์ฐ๋ฉด ๋๋ค.
# ์์ฝ
redux-thunk๋ ๋ฆฌ๋์์ ์ก์ ๊ฐ์ฒด๋ฅผ ๋ณด๋ด๋ ์ผ๋ฐ์ ์ธ ์ก์ ์์ฑ์์์ ํจ์ํํ(thunk)์ ์ก์ ์์ฑ์, ์ฆ ๋ด๋ถ์ dispatch, getState๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๊ฐ์ง๊ณ ์๋ ํจ์ ํํ๋ฅผ ๊ฐ์ง ์ก์ ์์ฑ์๋ฅผ ๋ฆฌ๋์์ ๋ณด๋ด๊ฒ ํด์ฃผ๋ ๋ฏธ๋ค์จ์ด ์ด๋ค.