μλ
νμΈμ, μ λ Reduxλ₯Ό 곡λΆνκ³ μλλ° ν₯λ―Έλ‘μ΄ λ¬Έμ μ μ§λ©΄νμ΅λκΉ? λ€λ₯Έ μμ
μμ λΉλκΈ° μμ² μ²΄μΈμ λ§λ€μ΄μΌ ν©λλ€.
1-getUser()
2-getPost()
λ‘κ·ΈμΈ μ¬μ©μ .then(dispatch({type:GET_POST_REQUEST})) ν 2κ°μ μ루μ
μ΄ μ€νλμμ΅λλ€.
λλ middleWareμμ κΈ°λ₯μ μμ±νμμμ€.
μ¬λ°λ₯΄κ² μννλ λ°©λ²?
μλ ! μ΄κ²μ λ¬Έμ μΆμ κΈ°μ΄λ©° μ§μ ν¬λΌμ΄ μλλλ€. SOμ λ¬λ¦¬ μ¬κΈ°μμ λ΅μ μμ΄λ²λ¦¬κΈ° λλ¬Έμ λ€μ λ²μ StackOverflowμ μ§λ¬Έν΄ μ£Όμ μ κ°μ¬ν©λλ€.
μ¦, Redux Thunk λ―Έλ€μ¨μ΄λ‘ μ€ν μ΄λ₯Ό μμ±νλ©΄ λ€μκ³Ό κ°μ΄ λΉλκΈ° μμ μμ±κΈ°λ₯Ό μμ±ν μ μμ΅λλ€.
// If you use Redux Thunk...
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
const store = createStore(reducer, applyMiddleware(thunk))
// You can define asynchronous action creators that return functions.
// We call such action creators "thunks":
export function getUser(id) {
// Redux Thunk will inject dispatch here:
return dispatch => {
// Reducers may handle this to set a flag like isFetching
dispatch({ type: 'GET_USER_REQUEST', id })
// Perform the actual API call
return fetchUser().then(
response => {
// Reducers may handle this to show the data and reset isFetching
dispatch({ type: 'GET_USER_SUCCESS', id, response })
},
error => {
// Reducers may handle this to reset isFetching
dispatch({ type: 'GET_USER_FAILURE', id, error })
// Rethrow so returned Promise is rejected
throw error
}
)
}
}
// Thunks can be dispatched, if Redux Thunk is applied,
// just like normal action creators:
store.dispatch(getUser(42));
// The return value of dispatch() when you dispatch a thunk *is*
// the return value of the inner function. This is why it's useful
// to return a Promise (even though it is not strictly necessary):
store.dispatch(getUser(42)).then(() =>
console.log('Fetched user and updated UI!')
)
// Here is another thunk action creator.
// It works exactly the same way.
export function getPost(id) {
return dispatch => {
dispatch({ type: 'GET_POST_REQUEST', id })
return fetchPost().then(
response => dispatch({ type: 'GET_POST_SUCCESS', id, response }),
error => {
dispatch({ type: 'GET_POST_FAILURE', id, error })
throw error
}
)
}
}
// Now we can combine them
export function getUserAndTheirFirstPost(userId) {
// Again, Redux Thunk will inject dispatch here.
// It also injects a second argument called getState() that lets us read the current state.
return (dispatch, getState) => {
// Remember I told you dispatch() can now handle thunks?
return dispatch(getUser(userId)).then(() => {
// Assuming this is where the fetched user got stored
const fetchedUser = getState().usersById[userId]
// Assuming it has a "postIDs" field:
const firstPostID = fetchedUser.postIDs[0]
// And we can dispatch() another thunk now!
return dispatch(getPost(firstPostID))
})
}
}
// And we can now wait for the combined thunk:
store.dispatch(getUserAndTheirFirstPost(43)).then(() => {
console.log('fetched a user and their first post')
})
// We can do this anywhere we have access to dispatch().
// For example, we can use this.props.dispatch, or put action
// creators right into the props by passing them to connect, like this:
// export default connect(mapStateToProps, { getUserAndTheirFirstPost })
μ΄κ²μ FAQμ λ£μ΄μΌ ν©λλ€.
μ΄ λ¬Έμ λ₯Ό λ€μκ³Ό κ°μ΄ ν΄κ²°νμ΅λλ€. μμ μμ μμ΄. Promise κ΅¬μ± μμλ₯Ό λ£μμ΅λλ€.
clickShowUserEvent(data) {
Promise.resolve(data.userAuth(data.login, data.password)) // dispatch
.then(function (response) {
data.showEvents(); //dispatch
return response;
})
.then(function(response){console.log("@RESPONSE",response);data.show(data)})
}
μ΄κ²μ΄ μ¬λ°λ₯Έ κ²°μ μ λκΉ?
μ΄κ²μ μμ μλνλ©° μ΄λ€ ν¨ν΄μ μ¬μ©ν μ§λ λΉμ μκ² λ¬λ € μμ΅λλ€.
@ar53n React μ»΄ν¬λνΈμ promiseκ° μλ ν¨ν΄μλ λͺ κ°μ§ κ²°ν¨μ΄ μμ΅λλ€.
catch
λΆλΆμ
λλ€. μ²λ¦¬λμ§ μμ κ±°λΆλ₯Ό λ°μ μ μμ΅λλ€.@sompylasar κ°μ¬ν©λλ€ Johnμ κ·νμ μ견μ κ°μ¬λ립λλ€. κ°λ¨ν μμ
μ μμ νκ³ μΆμ§ μμ΅λλ€. Authentication
λ° GetEvents
2κ°μ κ°λ¨ν μμ
μ΄ μμ΅λλ€. μ΄λ 2κ°μ λΉλκΈ° μμ²μ΄λ©° catch
λ ν¬ν¨ν©λλ€. κ΅¬μ± μμλ₯Ό ν΄λ¦νλ©΄ μ΄ μμ
λ§ νΈμΆλ©λλ€.
μ
export function userAuth(login, password) {
return (dispatch, getState) => {
console.log('STATE', getState())
let newState = dispatch(requestUserAuth(login, password))
return fetch(AUTH_URL + newState.queryParams, MY_INIT)
.then(response => response.json())
.then(function (json) { dispatch(receiveUserAuth(json)); return json})
.catch(error => dispatch(errorUserAuth(error)))
}
}
κ·Έλ¦¬κ³ μ°λ¦¬λ μ΄κ²μ κ°μ§κ³ μμ΅λλ€
λ΄κ° νλ Έλ€λ©΄ μ§μ ν΄ μ£ΌμΈμ. κ°μ¬ν©λλ€.
@ar53n κ·Έλ¬λ©΄ λ¬Έμ κ° ν΄κ²°λκ³ μμ μμ νλ‘μΈμ€κ° μΆμ λ©λλ€. κ΅¬μ± μμμ 무μ€λ¨ νλ‘μΈμ€ λ¬Έμ λ μ¬μ ν μ μ©λμ§λ§ κ΅¬μ± μμ λλ μμ μ½ν¬μμ μμν κ²½μ°μλ κ·Έλ€μ§ μ€μνμ§ μμ μ μμ΅λλ€.
@ar53n redux-dataloader λ₯Ό μ΄ν΄λ³Ό μλ μμ΅λλ€.
볡μ‘ν μ²΄μΈ λΉλκΈ° μμ
μ μν΄ μ€κ³λμμ΅λλ€.
λμμ΄ λκΈ°λ₯Ό λ°λλλ€!
μ¬κΈ°μ κ²μλ λͺ κ°μ§ κ°λ₯ν μ루μ μ΄ μμΌλ―λ‘ μ΄κ²μ λ«μ΅λλ€. μμ¦ redux-sagaλ₯Ό μ΄ν΄λ³΄κ³ μΆμ μλ μμ΅λλ€!
@gaearon λ μ μμλ μ¬λ μκ° μ¬νμ νκ³ μμ§ μμ΅λκΉ?
μλ₯Ό λ€μ΄ AJAX νΈμΆμ΄ μ²μμ μ€ν¨ν λ€μ μλ² μΈ‘μ μμ νκ³ λ€μ μ€ννλ €κ³ ν©λλ€.
@gaearon κ·νμ μ루μ
μ μλνμ§λ§ λͺ¨λ κ΅¬μ± μμμμ store.dispatch(...)
λ₯Ό νΈμΆνλ €κ³ ν λ(μ κ²½μ°μλ μΉμΈ μμ²μ μννκΈ° μν΄ LoginComponentμμ) λ€μ μ€λ₯κ° λ°μνμ΅λλ€.
undefined is not an object (evaluating '_AppNavigator.AppNavigator.router')
λκ° μλͺ»λ κ² κ°μ΅λλ€. λ€μκ³Ό κ°μ΄ μ‘μ μμ±κΈ°λ₯Ό μ€μ νμ΅λλ€.
// actions.tsx
export const ActionCreators = {
authenticate: (username: string, password: string) => {
return (dispatch) => {
return auth.login(username, password).then(
response => {
dispatch(navActionCreators.login(res))
return response
},
error => {
throw error
}
)
}
}
}
// LoginScreen.tsx (login method)
store.dispatch(authActions.authenticate(this.state.username, this.state.password))
.then((res) => {
this.setState({isLoading: false})
})
.catch((error: Error) => {
this.setState({
isLoading: false,
error: error ? error.message : 'Si Γ¨ verificato un\' errore.'
})
})
λ΄κ° 무μμ λμΉκ³ μμ΅λκΉ?
@bm-software: λμ μ€ν μ€λ²νλ‘μμ ν΄λΉ μ§λ¬Έμ ν΄μΌ ν©λλ€.
@ar53n λ° @sompylasar μ€λ μκ°μ΄ μ§λ¬μ§λ§ μ§κΈμ μ΄ ν¨ν΄μΌλ‘ μ΄λ €μμ κ²ͺκ³ μμ΅λλ€. κ·νμ μμμ @ar53n userAuth
fetch
$κ° μ€ν¨νλ©΄ userAuth
κ° νΈμΆλλ 체μΈμμ μ΄λ€ μΌμ΄ λ°μν©λκΉ?
.catch(error => dispatch(errorUserAuth(error)))
κ° errerUserAuth μμ
μ μ λ¬νλ κ²μ²λΌ 보μ
λλ€. νλ₯ν©λλ€. Reduxμμ μ΄κ²μ μΌλ°μ μΌλ‘ μ€λ₯λ₯Ό "μ²λ¦¬"νλ λ°©λ²μ
λλ€. κ·Έλ¬λ μμ μΈκΈν 체μΈμμ:
clickShowUserEvent(data) {
Promise.resolve(data.userAuth(data.login, data.password)) // dispatch
.then(function (response) {
data.showEvents(); //dispatch
return response;
})
.then(function(response){console.log("@RESPONSE",response);data.show(data)})
}
data.showEvents()
λ μ¬μ©μ μΈμ¦μ΄ μ€ν¨νλλΌλ _νμ_ νΈμΆλ©λλ€. λλ κ·Έκ²μ΄ λλΆλΆμ μ¬λλ€μ΄ κΈ°λνκ±°λ μνλ κ²μ΄λΌκ³ μκ°νμ§ μμ§λ§ Reduxμ μ€λ₯ μ²λ¦¬λ μΌλ°μ μΌλ‘ re-throwκ° μλ ββλμ€ν¨μΉλ‘ μνλκΈ° λλ¬Έμ μ€λ₯λ₯Ό μΌν€λ―λ‘ μ½μ 체μ΄λμ΄ μμλλ‘ μλνμ§ μμ΅λλ€.
λν λ€μ λμ§λ©΄ _μ΄λμλ μ±μ λͺ¨λ λ¨μΌ μμ
μμ±μ νΈμΆμμ .catch()
λ₯Ό ν΄μΌ ν©λλ€. λͺ¨λ μ€λ₯λ₯Ό λ€μ λμ§ μμ @gaearon μμ λ λ§μ§λ§μ λ€μμ μνν©λλ€.
// And we can now wait for the combined thunk:
store.dispatch(getUserAndTheirFirstPost(43)).then(() => {
console.log('fetched a user and their first post')
})
getUserAndTheirFirstPost
λ΄λΆμ ν° κ²°ν© μ²΄μΈμμ _anything_μ΄ μ€ν¨νλ©΄ "μ²λ¦¬λμ§ μμ μ½μ κ±°λΆ" μ€λ₯κ° λ°μν©λλ€.
μ μΌν λ΅μ λͺ¨λ κ³³μμ λ€μ λμ§ λ€μ .catch()
λ₯Ό λ€μ λμ§κ±°λ React 16 μ€λ₯ κ²½κ³λ₯Ό μ¬μ©νλ κ²μ΄λΌκ³ μκ°ν©λλ€.
@jasonrhodes
clickShowUserEvent(data) {
Promise.resolve(data.userAuth(data.login, data.password)) // dispatch
.then(function (response) {
data.showEvents(); //dispatch
data.showEvents()
λ μ¬μ©μ μΈμ¦μ΄ μ€ν¨νλλΌλ _νμ_ νΈμΆλ©λλ€.
μλμ, data.userAuth(data.login, data.password)
κ° κ²°κ΅ κ±°λΆλλ μ½μμ λ°ννλ©΄ νΈμΆλμ§ μμ΅λλ€. .then
μ λν 첫 λ²μ§Έ μΈμλ μ½μμ΄ μ΄νλ λ νΈμΆλκ³ ( onFulfilled
λΌκ³ ν¨), λ λ²μ§Έ μΈμλ μ½μμ΄ κ±°λΆλ λ νΈμΆλ©λλ€( onRejected
) β μ¬μ μ°Έμ‘° .
λ°λ©΄μ React 16 μ€λ₯ κ²½κ³λ promiseμ λμμ΄ λμ§ μμΌλ©° React λ΄λΆ μνκ° κΉ¨μ§μ§ μλλ‘ λκΈ°μ μΌλ‘ λ°μν μμΈλ§ catchν©λλ€.
@jasonrhodes λν Promise μΈκ³μ μ’μ μλ―Όμ΄ λμμμ€. νΈμΆμμκ² μ½μμ λ°ννκ±°λ(κ·Έλ° λ€μ μ€λ₯λ₯Ό μ²λ¦¬ν΄μΌ ν¨) .catch
λ₯Ό 첨λΆ(κ·Έλ¦¬κ³ μ½μμ΄ μμ±λ μ€λ₯λ₯Ό μ²λ¦¬)ν©λλ€.
κ·νμ μλ μ무 κ²λνμ§ μμ΅λλ€.
clickShowUserEvent(data) {
Promise.resolve(data.userAuth(data.login, data.password)) // dispatch
.then(function (response) {
data.showEvents(); //dispatch
return response;
})
.then(function(response){console.log("@RESPONSE",response);data.show(data)})
}
@sompylasar κ·Έκ²μ λ΄ μκ° μλλΌ μ΄ μ€λ λμ μλΆλΆμμ μλ΅νλ κ²μ λλ€. μκ°μ΄ λ§μ΄ μ§λ¬λ€λ κ²μ μκ³ μμ§λ§ Google κ²μμ ν΅ν΄ μ΄ μ€λ λλ₯Ό λ λ² μ΄μ μ νκΈ° λλ¬Έμ μ¬κΈ°μμ μ΄μ λνλ₯Ό μ°Έμ‘°νμ΅λλ€.
λ€μ 보면 userAuth
fetch
νΈμΆμ΄ μ€ν¨νλλΌλ data.showEvents()
λ _νμ_ νΈμΆλ©λλ€. μμ? userAuth
ν¨μ λ΄λΆμ Redux λ°©μμΌλ‘ μ€λ₯λ₯Ό μ²λ¦¬νλ .catch()
κ° μκΈ° λλ¬Έμ
λλ€.
μ΄κ²μ΄ λ΄ κ²μλ¬Όμ μμ μ
λλ€. λΉλκΈ° μμ
μμ μ€λ₯λ₯Ό ν¬μ°©νμ¬ μ€λ₯ μμ
μ μ λ¬ν λ λ μ΄μμ μ½μ 체μΈμ΄ μ¬λ°λ₯΄κ² μλνμ§ μλλ‘ μΌν€κ³ λ°©μ§ν©λκΉ? μλλ©΄ "μ²λ¦¬λμ§ μμ μ½μ κ±°λΆ"λ₯Ό νΌνκΈ° μν΄ λ¬΄μμ νλ ν΄λΉ μμ
μμ±μμ λͺ¨λ νΈμΆμλ₯Ό λ€μ λμ§κ³ κ°μ λ‘ .catch()
νμκ² μ΅λκΉ?
λν λ΄ κ²½νμ λ°λ₯΄λ©΄ λκ΅°κ°λ₯Ό μ¬μμ μ°κ²°νκΈ° μ μ λκ΅°κ°κ° μκ³ μλ κ²μ μ΄ν΄νλ κ²μ΄ μ’μ΅λλ€. μλ΅ν΄ μ£Όμ μ κ°μ¬ν©λλ€. μ κ° νν€μΉ μ€λλ λνλΌλ κ²μ μκ³ μμ§λ§ μΌλ§λ λμΉκΈ° μ¬μ΄μ§ μ μ μλ―μ΄ μ€μν λνμ λλ€!
@jasonrhodes
@sompylasar κ·Έκ²μ λ΄ μκ° μλλΌ μ΄ μ€λ λμ μλΆλΆμμ μλ΅νλ κ²μ λλ€. μκ°μ΄ λ§μ΄ μ§λ¬λ€λ κ²μ μκ³ μμ§λ§ Google κ²μμ ν΅ν΄ μ΄ μ€λ λλ₯Ό λ λ² μ΄μ μ νκΈ° λλ¬Έμ μ¬κΈ°μμ μ΄μ λνλ₯Ό μ°Έμ‘°νμ΅λλ€.
μκ² μ΅λλ€. μ£μ‘ν©λλ€. μ 체 λ§₯λ½μ κΈ°μ΅νμ§ λͺ»νμ΅λλ€.
userAuth
ν¨μ λ΄λΆμ Redux λ°©μμΌλ‘ μ€λ₯λ₯Ό μ²λ¦¬νλ.catch()
κ° μκΈ° λλ¬Έμ λλ€.
μκ² μ΅λλ€. κ·Έλ¬λ©΄ μ΄κ²μ΄ μλν λλ‘ μλνκ±°λ ν΄λΉ μ½μμ λ°ννκ³ νΈμΆ μ¬μ΄νΈμμ μ€λ₯λ₯Ό μ²λ¦¬νλ κ²½μ° .catch
λ₯Ό κ±°κΈ°μ λμ΄μλ μ λ©λλ€. κ·Έλ μ§ μμΌλ©΄ $ .catch
λ΄μ μ€λ₯λ₯Ό λ€μ λμ ΈμΌ ν©λλ€.
μ΄μ¨λ μ½ν¬ μ체λ μ°κ²°μ μ ν©νμ§ μμ΅λλ€. μ½ν¬ λ΄λΆμμ μ°κ²°νκ±°λ λ³΄λ€ λ³΅μ‘ν λΉλκΈ°μ μν¬νλ‘μ sagasλ₯Ό μ¬μ©ν΄μΌ ν©λλ€.
λλ μ μ λμ μ½μ μ¬μ¬μ κΉ¨λ λ¬Έμ μ 맀λ¬λ Έμ΅λλ€. μΌλ°μ μΌλ‘ λ΄ μμ μμ±μλ μ½ν¬μμ λ°νλ λμΌν http μμ²μ .then()μμ SUCCESS μμ μ λ΄λ³΄λ΄κ±°λ .catch()μμ FAILURE μμ μ λ΄λ³΄λ λλ€.
λ΄ μμ
μμ±μκ° catch λΈλ‘μΌλ‘ μ΄λνκ³ λ΄κ° this.props.myActionCreator().then(() => )
μ ν λλ§λ€ then λ΄λΆμ μ½λλ μμ²μ λ¬Έμ κ° μλλΌλ μ€νλ©λλ€.
μ΄λ₯Ό μ€λͺ νκΈ° μν΄ μ λ νμ ν΄λΉ μμ μμ±μμ FAILURE μ¬λ‘μ μ€μ λ μ± μνμ μ€λ₯ λ³μλ₯Ό νμΈνμ΅λλ€. κ·Έλ¬λ μ¬λ¬ μ‘μ μ μμ, νΉν λ€λ₯Έ μ¬λμκ² μμ‘΄νλ μ μμλ₯Ό νΈμΆνλ©΄ μν©μ΄ 볡μ‘ν΄μ§λλ€. λ§μ μ€λ₯ λ³μλ₯Ό νμΈνλ if λ¬Έμ΄ μμ΄μΌ νμ΅λλ€.
μ‘μ μμ±μ λ°ν κ°μ λν catch λΈλ‘μμ μ€λ₯λ₯Ό λ€μ throwνμ¬ μ½μ 체μΈμ κΉ¨λ¨λ¦¬μ§ μλλ€λ μ¬μ€μ΄ λ§μμ λλλ€. κ·Έλ¬λ μ΄λ₯Ό μν΄μλ μ‘μ μμ±μκ° νΈμΆλλ React κ΅¬μ± μμμμ .catch()λ₯Ό μ¬μ©ν΄μΌ ν©λλ€. μ€λ₯ λ³μκ° κ°μκΈ°μμ FAILURE μμ μ μ²λ¦¬νμ¬ μ΄λ―Έ μ€μ λμ΄ μκΈ° λλ¬Έμ ν΄λΉ catch λΈλ‘μ μ무 κ²λ μμ±νμ§ μμ κ²μ λλ€.
@jasonrhodes , @sompylasar μ¬λ¬λΆ, λ€μ λμ§λ μ κ·Ό λ°©μμ μ¬μ©νκ³ React κ΅¬μ± μμμμ μμ μμ±μ νΈμΆμ μ½μ 체μΈμ λΉ .catch() λΈλ‘μ λ°°μΉνλ κ²μ΄ μ’μ΅λλ€.
@nbkhope μμ§ν λ§ν΄μ μ΄κ²μ΄ Reduxμ κ°μ₯ ν° λ¬Έμ μμΌλ©° μ§κΈκΉμ§ μ’μ λ΅μ μ°Ύμ§ λͺ»νμ΅λλ€. λ λμμ΄ λμ§ λͺ»ν΄ μ£μ‘ν©λλ€!
μ¬λ¬λΆ, μ΄ κΈ°μ¬μμ μ½ν¬ λμμ μ°Ύμ μ μμ΅λλ€. https://decembersoft.com/posts/what-is-the-right-way-to-do-asynchronous-operations-in-redux/
@gaearon
첫 λ²μ§Έ λ΅λ³κ³Ό κ΄λ ¨νμ¬ μ½μ λμ λΉλκΈ° λ° λκΈ°λ₯Ό μ¬μ©νλ κ²½μ° μ΄λ»κ² λ³νν΄μΌ ν©λκΉ? λ€μκ³Ό κ°μ κ²:
export const funcA = () => {
return async (dispatch) => {
const data = await doSomething(...)
dispatch({ action: DID_SOMETHING, payload: data })
}
}
export const funcB = () => {
return async (dispatch) => {
const data = await doSomethingElse(...)
dispatch({ action: DID_SOMETHING_ELSE, payload: data })
}
}
export const funcC = () => {
return async (dispatch) => {
const data = await doSomethingMore(...)
dispatch({ action: DID_SOMETHING_MORE, payload: data })
}
}
// how to chain funcA, funcB and funcC
const myFunc = () => {
// execute funcA
// when complete execute funcB
// when complete execute funcC
}
@yingdongzhang λ€μκ³Ό κ°μ΄ μ°κ²°ν μ μμ΅λλ€.
const myFunc = () => {
return async (dispatch) => {
try {
await dispatch(funcA())
await dispatch(funcB())
await dispatch(funcC())
} catch (error) {
//error handling
}
}
}
@Boomxx κ°μ¬ν©λλ€ μμλλ‘ μλν©λλ€.
fetch all posts of the user
μ μ΄λ»κ² ν΄μΌ νλμ§ κΆκΈν©λλ€.
@km16 : μ΄κ²μ μ§μ μμ€ν μ΄ μλ λ²κ·Έ μΆμ κΈ°μ λλ€. μ¬μ©λ²μ κ΄ν μ§λ¬Έμ Stack Overflow λλ Reactifluxλ₯Ό μ¬μ©νμ¬ λμμ€ μ€λΉκ° λ λ λ§μ μ¬λλ€μ΄ μμ΅λλ€. λ λμ λ΅λ³μ λ 빨리 μ»μ μ μμ΅λλ€. κ°μ¬ ν΄μ!
κ°μ₯ μ μ©ν λκΈ
μλ ! μ΄κ²μ λ¬Έμ μΆμ κΈ°μ΄λ©° μ§μ ν¬λΌμ΄ μλλλ€. SOμ λ¬λ¦¬ μ¬κΈ°μμ λ΅μ μμ΄λ²λ¦¬κΈ° λλ¬Έμ λ€μ λ²μ StackOverflowμ μ§λ¬Έν΄ μ£Όμ μ κ°μ¬ν©λλ€.
μ¦, Redux Thunk λ―Έλ€μ¨μ΄λ‘ μ€ν μ΄λ₯Ό μμ±νλ©΄ λ€μκ³Ό κ°μ΄ λΉλκΈ° μμ μμ±κΈ°λ₯Ό μμ±ν μ μμ΅λλ€.
μ΄κ²μ FAQμ λ£μ΄μΌ ν©λλ€.