React 實踐項目 (一)
React 實踐項目 (二)
React 實踐項目 (三)
export const auth = (state = initialState, action = {}) => { switch (action.type) { case LOGIN_USER: return state.merge({ 'user': action.data, 'error': null, 'token': null, }); case LOGIN_USER_SUCCESS: return state.merge({ 'token': action.data, 'error': null }); case LOGIN_USER_FAILURE: return state.merge({ 'token': null, 'error': action.data }); default: return state } };
Sagas 監聽發起的 action,然后決定基于這個 action 來做什么:是發起一個異步調用(比如一個 Ajax 請求),還是發起其他的 action 到 Store,甚至是調用其他的 Sagas。
具體到這個登陸功能就是我們在登陸彈窗點擊登陸時會發出一個 LOGIN_USER
action,Sagas 監聽到 LOGIN_USER
action,發起一個 Ajax 請求到后臺,根據結果決定發起 LOGIN_USER_SUCCESS
action 還是LOGIN_USER_FAILURE
action
接下來,我們來實現這個流程
在 package.json 中添加 redux-saga
依賴
"redux-saga": "^0.15.4"
修改 src/redux/store/store.js
/** * Created by Yuicon on 2017/6/27. */ import {createStore, applyMiddleware } from 'redux'; import createSagaMiddleware from 'redux-saga' import reducer from '../reducer/reducer'; import rootSaga from '../sagas/sagas'; const sagaMiddleware = createSagaMiddleware(); const store = createStore( reducer, applyMiddleware(sagaMiddleware) ); sagaMiddleware.run(rootSaga); export default store;
Redux-saga 使用 Generator 函數實現
創建 src/redux/sagas/sagas.js
/** * Created by Yuicon on 2017/6/28. */ import { takeLatest } from 'redux-saga/effects'; import {registerUserAsync, loginUserAsync} from './users'; import {REGISTER_USER, LOGIN_USER} from '../action/users'; export default function* rootSaga() { yield [ takeLatest(REGISTER_USER, registerUserAsync), takeLatest(LOGIN_USER, loginUserAsync) ]; }
我們可以看到在 rootSaga 中監聽了兩個 action 登陸和注冊 。
在上面的例子中,takeLatest 只允許執行一個 loginUserAsync 任務。并且這個任務是最后被啟動的那個。 如果之前已經有一個任務在執行,那之前的這個任務會自動被取消。
如果我們允許多個 loginUserAsync 實例同時啟動。在某個特定時刻,我們可以啟動一個新 loginUserAsync 任務, 盡管之前還有一個或多個 loginUserAsync 尚未結束。我們可以使用 takeEvery 輔助函數。
獲取 Store state 上的數據
selectors.js
/** * Created by Yuicon on 2017/6/28. */ export const getAuth = state => state.auth;
api
api.js
/** * Created by Yuicon on 2017/7/4. * */ /** * 這是我自己的后臺服務器,用 Java 實現 * 項目地址: * 文檔:http://139.224.135.86:8080/swagger-ui.html#/ */ const getURL = (url) => `http://139.224.135.86:8080/${url}`; export const login = (user) => { return fetch(getURL("auth/login"), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(user) }).then(response => response.json()) .then(json => { return json; }) .catch(ex => console.log('parsing failed', ex)); };
創建 src/redux/sagas/users.js
/** * Created by Yuicon on 2017/6/30. */ import {select, put, call} from 'redux-saga/effects'; import {getAuth, getUsers} from './selectors'; import {loginSuccessAction, loginFailureAction, registerSuccessAction, registerFailureAction} from '../action/users'; import {login, register} from './api'; import 'whatwg-fetch'; export function* loginUserAsync() { // 獲取Store state 上的數據 const auth = yield select(getAuth); const user = auth.get('user'); // 發起 ajax 請求 const json = yield call(login.bind(this, user), 'login'); if (json.success) { localStorage.setItem('token', json.data); // 發起 loginSuccessAction yield put(loginSuccessAction(json.data)); } else { // 發起 loginFailureAction yield put(loginFailureAction(json.error)); } }
select(selector, ...args)
用于獲取Store state 上的數據put(action)
發起一個 action 到 Storecall(fn, ...args)
調用 fn 函數并以 args 為參數,如果結果是一個 Promise,middleware 會暫停直到這個 Promise 被 resolve,resolve 后 Generator 會繼續執行。 或者直到 Promise 被 reject 了,如果是這種情況,將在 Generator 中拋出一個錯誤。
Redux-saga 詳細api文檔
我在工作時用的是 Redux-Thunk, Redux-Thunk 相對來說更容易實現和維護。但是對于復雜的操作,尤其是面對復雜異步操作時,Redux-saga 更有優勢。到此我們完成了一個 Redux-saga 的入門教程,Redux-saga 還有很多奇妙的地方,
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com