以前作了個好電影蒐集的小應用,前端採用react,後端採用express+mongodb,最近又將組件間的狀態管理改爲了redux,並加入了redux-saga來管理異步操做,記錄一些總結
源碼前端
前端使用了react,redux加redux-saga,對redux簡單總結一下,同時記錄一個先後接口調用有依賴關係的問題node
一句話總結redux,我覺的就是將組件之間的縱向的props傳遞和父子組件間的state愛恨糾纏給打平了,將一種縱向關係轉變成多個組件和一個獨立出來的狀態對象直接交互
,這樣以後,代碼結構確實看上去更加清晰了。react
redux的核心概念,action,reducer,和storegit
action就是說明我要操做一個狀態了,怎麼操做是reducer的事,而全部狀態存儲在store中,store發出動做並交由指定的reducer來處理
github
redux強制規範了咱們對狀態的操做,只能在action和reducer這些東西中,這樣,本來錯綜複雜的業務邏輯處理就換了個地,限制在了action和reducer中,組件看上去就很乾淨了。其實,該複雜的東西在哪放都複雜,只不過如今更清晰一點web
使用redux很差的地方就是太繁瑣了,定義各類action,connect各類組件。。。。。如今又出來一個Mobx,不明覺厲,反正你們都說好~redis
redux-saga用來處理異步調用啥的,藉助於generator,讓異步代碼看起來更簡潔,經常使用的有take,takeLatest,takeEvery,put,call,fork,select
,使用過程當中遇到一個接口調用有先後依賴關係的問題,比較有意思mongodb
描述一下:express
function* checkLogin() { const res = yield Util.fetch('/api/user/checkLogin') yield put(recieveCheckLogin(!res.code)) if (!res.code) { //已登陸 yield put(fetchUinfo()) } } export function* watchCheckLogin() { yield takeLatest(CHECK_LOAGIN, checkLogin) }
/api/movies/${id}
接口獲取電影信息,若是用戶是登陸狀態的話,還會發起一個獲取電影附件信息的接口/api/movies/${id}/attach
,整個步驟寫在一個generator中 function* getItemMovie(id) { return yield Util.fetch(`/api/movies/${id}`) } function* getMovieAttach(id) { return yield Util.fetch(`/api/movies/${id}/attach`) } function* getMovieInfo(action) { const { movieId } = action let { login } = yield select(state => state.loginStatus) const res = yield call(getItemMovie, movieId) yield put(recieveItemMovieInfo(res.data[0])) if (res.data[0].attachId && login) { const attach = yield call(getMovieAttach, movieId) yield put(recieveMovieAttach(attach.data[0])) } } export function* watchLoadItemMovie() { yield takeLatest(LOAD_ITEM_MOVIE, getMovieInfo) }
state.loginStatus
狀態仍是false,上面就沒走到if中function* getMovieInfo(action) { const { movieId } = action let { login } = yield select(state => state.loginStatus) const res = yield call(getItemMovie, movieId) yield put(recieveItemMovieInfo(res.data[0])) // if (!login) { // //刷新頁面的時候,若是此時checklogin接口還沒返回數據或還沒發出,應觸發一個checklogin // //checklogin返回後才能獲得login狀態 // yield put({ // type: CHECK_LOAGIN // }) // const ret = yield take(RECIEVE_CHECK_LOAGIN) // login = ret.loginStatus // } if (res.data[0].attachId && login) { const attach = yield call(getMovieAttach, movieId) yield put(recieveMovieAttach(attach.data[0])) } }
//將獲取附件的動做從 getMovieInfo這個generator中分離出來 function* getMovieInfo(action) { const { movieId } = action const res = yield call(getItemMovie, movieId) yield put(recieveItemMovieInfo(res.data[0])) } function* watchLoadItemMovie() { yield takeLatest(LOAD_ITEM_MOVIE, getMovieInfo) } function* watchLoadAttach() { while (true) { const { movieId } = yield take(LOAD_MOVIE_ATTACH) const { attachId } = yield select(state => state.detail.movieInfo) const attach = yield call(getMovieAttach, movieId) yield put(recieveMovieAttach(attach.data[0])) } } //組件中 componentWillUpdate(nextProps) { if (nextProps.loginStatus && (nextProps.movieInfo!==this.props.movieInfo)) { //是登陸狀態,而且movieInfo已經返回時 const { id } = this.props.match.params this.props.loadMovieAttach(id) } }
後端採用express和mongodb,也用到了redis,主要技術點有使用pm2來管理node應用及部署代碼
,mongodb中開啓身份認證,使用token+redis來作身份認證、在node中寫了寫單元測試,仍是值得記錄一下的json
基於token的認證流程
這裏採用jsonwebtoken來生成token,
jwt.sign(payload, secretOrPrivateKey, [options, callback])
使用express-jwt驗證token(驗證成功會把token信息放在request.user中)
express_jwt({ secret: SECRET, getToken: (req)=> { if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { return req.headers.authorization.split(' ')[1]; } else if (req.query && req.query.token) { return req.query.token; } return null; } }
爲何使用redis
**採用jsonwebtoken生成token時能夠指定token的有效期,而且jsonwebtoken的verify方法也提供了選項來更新token的有效期,
但這裏使用了express_jwt中間件,而express_jwt不提供方法來刷新token**
思路:
測試覆蓋了全部接口,在開發中,由於沒什麼進度要求就慢慢寫了,寫完一個接口就去寫一個測試,測試寫也還算詳細,等測試經過了再前端調接口,整個過程仍是挺有意思的
mocha 是一個node單元測試框架,相似於前端的jasmine,語法也相近
supertest 用來測試node接口的庫
should nodejs斷言庫,可讀性很高
測試的一個例子,篇幅太長,就不放在這了
喜歡能夠關注下,萬一有福利呢。。。。。