之前的 react-redux基礎(chǔ)用法 中基本是同步的修改 redux 中的 state 數(shù)據(jù)猩系,今天補(bǔ)充如何進(jìn)行異步操作园爷。
首先安裝 thunk 和 logger 兩個 redux 的插件
$ npm i redux-thunk
$ npm i redux-logger
結(jié)合上一篇文章的內(nèi)容,此時我們已經(jīng)有了以下文件目錄
src
| -- api
| -- | -- api.js
| -- | -- user.js
| -- store
| -- | -- index.js
| -- reducers
| -- | -- user.js
| -- | -- index.js
| -- action
| -- | -- constants.js
| -- | -- user.js
| -- index.js
| -- app.js
這里由于項目的關(guān)系我直接使用用戶登錄這一模塊來作為案例刨仑。
那么按照之前的思路一步步來——
- 創(chuàng)建 store 需要使用到
import { createStore } from 'react-redux'
// 結(jié)合異步操作需要額外使用到 applyMiddleware 方法
import { applyMiddleware } form 'react-redux'
// 再將之前安裝的兩個 redux 插件引入
import thunk from 'redux-thunk'
import logger from 'redux-logger'
// 引入合并好的 reducers
import reducers from '../'
// 歷史版本
// const store = createStore(rootReducer)
// 結(jié)合插件,創(chuàng)建一個 store 實例
const store = createStore(rootReducer, applyMiddleware(thunk, logger))
export default store
- 設(shè)置 reducers
- index.js
index.js 文件還是老樣子姑原,把其他單獨的 reducer 文件引入,使用combineReducers
將其合并成一個整體 - user.js
user.js 文件的變動沒有太大,只是對于修改 state 數(shù)據(jù)時采用了對象深拷貝的辦法园欣。這里推薦使用 lodash 的 cloneDeep() 方法
import { USER_LOGIN_SUCCESS, USER_RESET } from '../actions/constants'
import _ from 'lodash'
const initialState = {
info: null,
token: null,
}
/**
* 用于同步更新與用戶登錄狀態(tài)相關(guān)的狀態(tài)數(shù)據(jù)
* state 更新前的舊狀態(tài)
* action 普通對象,描述如何更新狀態(tài)休蟹,有 type 和 payload 屬性
* @return 返回更新后的狀態(tài)
*/
export default (state = initialState, { type, payload }) => {
// 對原 state 實行深拷貝
const copy = _.cloneDeep(initialState)
switch (type) {
case USER_LOGIN_SUCCESS: // 登陸成功
copy.info = payload.info
copy.token = payload.token
return copy
case USER_RESET:
copy.info = null,
copy.token = null
return copy
default:
return state
}
}
- action.js
鑒于 constants.js 只是對于判斷常量的存儲沸枯,所以不過多展示
按照之前的思路,對于用戶是否登錄成功赂弓,這里一般有兩種判斷
export const loginSuccessAction = (user) => ({
type: USER_LOGIN_SUCCESS,
payload: user,
})
export const userResetAction = (user) => ({
type: USER_RESET,
})
但是在頁面的使用中并不是直接使用了绑榴,既然講出來了,肯定是要結(jié)合 axios 請求一起操作盈魁。所以在下方
* 定義異步 Action 創(chuàng)建函數(shù)翔怎,在 action creator 中也可以返回一個函數(shù)
* 該返回的函數(shù)會自動被 redux-thunk 中間件調(diào)用執(zhí)行。在 thunk 中間件
* 調(diào)用返回函數(shù)執(zhí)行時杨耙,會傳遞 dispatch 參數(shù)
// 引入 api 目錄下 user.js 文件中與登錄相關(guān)的 loginAsync 函數(shù)
import { loginAsync } from '../api/user'
// 重新定義一個函數(shù)赤套,函數(shù)中返回一個回調(diào)函數(shù)
// 這個回調(diào)函數(shù)的參數(shù)是 dispatch,用于調(diào)用定義的 action 方法
export const loginAsyncAction = (user) => (dispatch) => {
// 這里用了 ant desgin 的組件珊膜,各需所求
loginAsync(user)
.then((data) => {
// 如果沒有查詢到匹配用戶
if (data.length === 0) {
// 提示
notification['error']({
message: '登錄錯誤',
description:
'請輸入正確的賬戶或密碼.',
})
// 調(diào)用 用戶重置
dispatch({
type: USER_RESET,
})
} else {
// 提取 姓名 token 和 id
const res = {
info: data[0].name,
token: data[0].token,
}
localStorage.setItem('loginInfo', JSON.stringify(res))
dispatch(loginSuccessAction(res))
}
})
}
基本新增的東西就只有這些了于毙,需要在哪些組件使用就用 connect
方法映射一下。
另外記得
如果 mapStateToProps 不需要參數(shù)只能給 null
然后 hoc 成下面的寫法辅搬,不然會報錯的
connect(mapStateToProps, mapDispatchToProps)(Login)