成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

react技術(shù)棧實踐(從前到后擼一個電影搜集應用)

tigerZH / 2193人閱讀

摘要:其實,該復雜的東西在哪放都復雜,只不過現(xiàn)在更清晰一點使用不好的地方就是太繁瑣了,定義各種各種組件。。。。。

之前做了個好電影搜集的小應用,前端采用react,后端采用express+mongodb,最近又將組件間的狀態(tài)管理改成了redux,并加入了redux-saga來管理異步操作,記錄一些總結(jié)
在線地址 手機模式

源碼

主要功能

爬取豆瓣電影信息并錄入MongoDB

電影列表展示,分類、搜索

電影詳情展示及附件管理

注冊、登錄

權(quán)限控制,普通用戶可以錄入、收藏,administrator錄入、修改、刪除

用戶中心,我的收藏列表

一些總結(jié) 前端

前端使用了react,redux加redux-saga,對redux簡單總結(jié)一下,同時記錄一個前后接口調(diào)用有依賴關(guān)系的問題

redux

一句話總結(jié)redux,我覺的就是將組件之間的縱向的props傳遞和父子組件間的state愛恨糾纏給打平了,將一種縱向關(guān)系轉(zhuǎn)變成多個組件和一個獨立出來的狀態(tài)對象直接交互,這樣之后,代碼結(jié)構(gòu)確實看上去更加清晰了。

redux的核心概念,action,reducer,和store

action就是說明我要操作一個狀態(tài)了,怎么操作是reducer的事,而所有狀態(tài)存儲在store中,store發(fā)出動作并交由指定的reducer來處理

redux強制規(guī)范了我們對狀態(tài)的操作,只能在action和reducer這些東西中,這樣,原本錯綜復雜的業(yè)務邏輯處理就換了個地,限制在了action和reducer中,組件看上去就很干凈了。其實,該復雜的東西在哪放都復雜,只不過現(xiàn)在更清晰一點

使用redux不好的地方就是太繁瑣了,定義各種action,connect各種組件。。。。?,F(xiàn)在又出來一個Mobx,不明覺厲,反正大家都說好~

redux-saga

redux-saga用來處理異步調(diào)用啥的,借助于generator,讓異步代碼看起來更簡潔,常用的有take,takeLatest,takeEvery,put,call,fork,select,使用過程中遇到一個接口調(diào)用有前后依賴關(guān)系的問題,比較有意思

描述一下:

有一個接口/api/user/checkLogin,用來判斷是否登錄,在最外層的組件的componentDidMount中觸發(fā)action來發(fā)起這個請求,并且接口返回狀態(tài)是登錄的話,還要發(fā)一個獲取用戶信息的

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)
}

然后我有一個電影詳情頁組件,在這個組件的componentDidMount中會發(fā)起/api/movies/${id}接口獲取電影信息,如果用戶是登錄狀態(tài)的話,還會發(fā)起一個獲取電影附件信息的接口/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)
}

用戶登錄了,進到詳情,流程正常,但如果在詳情頁刷新了頁面,獲取附件的接口沒觸發(fā),原因是此時checkLogin接口還沒返回結(jié)果,state.loginStatus狀態(tài)還是false,上面就沒走到if中

一開始想著怎么控制一些generator中yield的先后順序來解決(如果用戶沒有登錄的話,再發(fā)一個CHECK_LOAGIN,結(jié)果返回了流程再繼續(xù)),但存在CHECK_LOAGIN調(diào)用兩次,如果登錄了,還會再多一次獲取用戶信息的接口調(diào)用的情況,肯定不行

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接口還沒返回數(shù)據(jù)或還沒發(fā)出,應觸發(fā)一個checklogin
    //     //checklogin返回后才能得到login狀態(tài)
    //     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]))
    }
}

最終的辦法,分解generator的職責,componentWillUpdate中合適的觸發(fā)獲取附件的動作

//將獲取附件的動作從 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)) {
            //是登錄狀態(tài),并且movieInfo已經(jīng)返回時
            const { id } = this.props.match.params
            this.props.loadMovieAttach(id)
        }
}

總結(jié),合理使用組件的鉤子函數(shù),generator中不要處理太多操作,增加靈活性

后端

后端采用express和mongodb,也用到了redis,主要技術(shù)點有使用pm2來管理node應用及部署代碼,mongodb中開啟身份認證,使用token+redis來做身份認證、在node中寫了寫單元測試,還是值得記錄一下的

使用 jwt + redis 來做基于token的用戶身份認證

基于token的認證流程

客戶端發(fā)起登錄請求

服務端驗證用戶名密碼

驗證成功服務端生成一個token,響應給客戶端

客戶端之后的每次請求header中都帶上這個token

服務端對需要認證的接口要驗證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**

思路:

客戶端請求登錄成功,生成token

將此token保存在redis中,設(shè)置redis的有效期(例如1h)

新的請求過來,先express_jwt驗證token,驗證成功, 再驗證token是否在redis中存在,存在說明有效

有效期內(nèi)客戶端新的請求過來,提取token,更新此token在redis中的有效期

客戶端退出登錄請求,刪除redis中此token

具體代碼

使用 mocha + supertest + should 來寫單元測試

測試覆蓋了所有接口,在開發(fā)中,因為沒什么進度要求就慢慢寫了,寫完一個接口就去寫一個測試,測試寫也還算詳細,等測試通過了再前端調(diào)接口,整個過程還是挺有意思的

mocha 是一個node單元測試框架,類似于前端的jasmine,語法也相近

supertest 用來測試node接口的庫

should nodejs斷言庫,可讀性很高

測試的一個例子,篇幅太長,就不放在這了

最后

喜歡可以關(guān)注下,萬一有福利呢。。。。。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92233.html

相關(guān)文章

  • 技術(shù):小菜前端的技術(shù)是如何規(guī)劃和演進的

    摘要:本文以管理者的視角,與大家分享下我自年月入職小菜后,與前端同學一起是如何規(guī)劃團隊的技術(shù)棧的,這條技術(shù)棧上的技能點又是如何在不同童鞋不同業(yè)務中生長出來的。 Scott 近兩年無論是面試還是線下線上的技術(shù)分享,遇到許許多多前端同學,由于團隊原因,個人原因,職業(yè)成長,技術(shù)方向,甚至家庭等等原因,在理想國與現(xiàn)實之間,在放棄與堅守之間,搖擺不停,心酸硬抗,大家可以找我聊聊南聊聊北,對工程師的宿命...

    betacat 評論0 收藏0
  • 《從零構(gòu)建前后分離 WEB 項目》 序 - 開源的意義

    摘要:盡量按照前端后端部署運維來講,當然中途涉及到跨域這種前后協(xié)調(diào)的還是無法避免捎帶一筆。關(guān)于我目前在寫從零構(gòu)建前后分離項目系列,修正和補充以此為準不斷更新的項目實踐地址彩蛋提前預覽下一章傳送門 序: 開源的意義 本系列提前首發(fā)地址 背景 從事了近4年的互聯(lián)網(wǎng)行業(yè),逐漸擔當過團隊的前端到后端的負責人,和大家一樣從小白逐漸的成長起來,回首望去幾年前的博客還是那么稚嫩。 回首這幾年: 從一個ja...

    seasonley 評論0 收藏0
  • 《從零構(gòu)建前后分離 WEB 項目》 序 :開源的意義

    摘要:從前端到后端到運維,經(jīng)歷了幾次前后端架構(gòu)的演變,踩了無數(shù)的坑,度過無數(shù)難免的夜。為了工作或?qū)W習,確實造過一些輪子,前端的后端的,也開源出來過覺得能提高生產(chǎn)力的。 showImg(https://segmentfault.com/img/bVbgeXP?w=713&h=275); 序: 開源的意義 本系列提前首發(fā)地址 背景 從事了近4年的互聯(lián)網(wǎng)行業(yè),逐漸擔當過團隊的前端到后端的負責人,和...

    J4ck_Chan 評論0 收藏0
  • 前端每周清單第 41 期 : Node 與 Rust、OpenCV 的火花,網(wǎng)絡安全二三事

    摘要:的網(wǎng)站仍然使用有漏洞庫上周發(fā)布了開源社區(qū)安全現(xiàn)狀報告,發(fā)現(xiàn)隨著開源社區(qū)的日漸活躍,開源代碼中包含的安全漏洞以及影響的范圍也在不斷擴大。與應用安全是流行的服務端框架,本文即是介紹如何使用以及其他的框架來增強應用的安全性。 showImg(https://segmentfault.com/img/remote/1460000012181337?w=1240&h=826); 前端每周清單專注...

    syoya 評論0 收藏0
  • 前端閱讀 - 收藏集 - 掘金

    摘要:實現(xiàn)不定期更新技巧前端掘金技巧,偶爾更新。統(tǒng)一播放效果實現(xiàn)打字效果動畫前端掘金前端開源項目周報前端掘金由出品的前端開源項目周報第四期來啦。 Web 推送技術(shù) - 掘金騰訊云技術(shù)社區(qū)-掘金主頁持續(xù)為大家呈現(xiàn)云計算技術(shù)文章,歡迎大家關(guān)注! 作者:villainthr 摘自 前端小吉米 伴隨著今年 Google I/O 大會的召開,一個很火的概念--Progressive Web Apps ...

    lingdududu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<