React在Github上已经有接近70000的 star 数了,是目前最热门的前端框架。而我学习React也有一段时间了,如今就开始用 React+Redux 进行实战!html
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。react
具体到这个登录功能就是咱们在登录弹窗点击登录时会发出一个 LOGIN_USER
action,Sagas 监听到 LOGIN_USER
action,发起一个 Ajax 请求到后台,根据结果决定发起 LOGIN_USER_SUCCESS
action 仍是LOGIN_USER_FAILURE
actiongit
接下来,咱们来实现这个流程es6
在 package.json 中添加 redux-saga
依赖github
"redux-saga": "^0.15.4"
ajax
修改 src/redux/store/store.js
json
/** * 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 函数实现redux
建立 src/redux/sagas/sagas.jsapi
/** * 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. * https://github.com/Yuicon */ /** * 这是我本身的后台服务器,用 Java 实现 * 项目地址:https://github.com/DigAg/digag-server * 文档: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 还有不少奇妙的地方,你们能够自行探索。