React:快速上手(7)——使用中間件實現異步操作
本文參考鏈接:Stack Overflow
redux-thunk
我們使用store.dispath進行派發時,只能傳遞一個普通對象進去,如下:
store.dispatch({ type: 'INCREMENT' })
但是,在使用redux-thunk中間件后,我們就可以傳遞一個函數進去
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
const store = createStore(
reducer,
applyMiddleware(thunk)
)
store.dispatch(function (dispatch) {
// ... which themselves may dispatch many times
dispatch({ type: 'INCREMENT' })
dispatch({ type: 'INCREMENT' })
dispatch({ type: 'INCREMENT' })
setTimeout(() => {
// ... even asynchronously!
dispatch({ type: 'DECREMENT' })
}, 1000)
})
啟用此中間件后,如果您dispatch一個函數,Redux Thunk中間件會將dispatch作為參數傳進該函數中去。在這個函數中,我們派發了多個action,甚至可以異步執行一些操作,比如延遲1000ms,派發action。那我們執行異步操作,就是通過這個中間件來實現的。
Action Creator
我們最好把action封裝到函數中,即(Action Creater),來提高靈活性以及防止我們拼寫錯誤。對於對象,我們可以直接如下寫:
function showNotification(id, text) {
return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
return { type: 'HIDE_NOTIFICATION', id }
}
那么這樣一個函數式的action,我們也可以將其封裝到一個函數中,它返回一個函數式的action
let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
return function (dispatch) {
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
}
那么,我們在調用它的時候是需要手動傳入一個dispatch的。
showNotificationWithTimeout('You just logged in.')(this.props.dispatch)
如果啟用了Redux Thunk中間件,則只要你嘗試dispatch函數而不是對象,中間件就會使用調度方法本身作為第一個參數來調用該函數,也就是我們可以這樣寫:
// component.js
this.props.dispatch(showNotificationWithTimeout('You just logged in.'))
配合React Redux的connect
Redux可以自動識別出這樣的“特殊”Action Creator(我們稱之為Thunk Action Creator),我們現在可以在任何我們使用常規動作創建者的地方使用它們。例如,我們可以將它們與connect()一起使用:
// actions.js
function showNotification(id, text) {
return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
return { type: 'HIDE_NOTIFICATION', id }
}
let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
return function (dispatch) {
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
}
// component.js
import { connect } from 'react-redux'
// ...
this.props.showNotificationWithTimeout('You just logged in.')
// ...
export default connect(
mapStateToProps,
{ showNotificationWithTimeout }
)(MyComponent)
在thunk中獲取狀態
Redux Thunk提供了一種方法來獲取Redux store的state。除了dispatch之外,它還將getState作為第二個參數傳遞給您從thunk action creator返回的函數。這讓thunk讀取store的當前state。
let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
return function (dispatch, getState) {
// Unlike in a regular action creator, we can exit early in a thunk
// Redux doesn’t care about its return value (or lack of it)
if (!getState().areNotificationsEnabled) {
return
}
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
}