從零開始編寫React-Express單頁博客應用(學習總結)

React-Express單頁博客應用編寫總結

好久以前就想寫一個博客應用.
在一開始想要直接用expressejs模板直接寫, 可是暑假一開始的時候不當心入了react的坑, 因此就一不作二不休直接用react寫. 那既然用了react, 不寫個單頁應用也過意不去了...(不
前先後後寫了將近兩個星期, 如今看來這實際上是一個很容易的應用. 可是鑑因而第一次用react, 對於nodejs也不是特別熟悉, 因此走了很多冤枉路. 其中也有不少次以爲想放棄, 不過最終仍是寫下來了. 雖然仍是有很多瑕疵, 不過也算給本身一個交代吧.
我的博客網站的地址爲: harryfyodor.tk
下面會從幾個方面把我整個編寫的過程的一些經驗記錄下來, 主要是記錄本身的學習過程, 編寫中遇到的困難以及解決, 以及一些學習/複習資料的整理分享. 也但願給各位和我同樣的初學者一點點借鑑的經驗.
(我的感受比較好的學習方式就是本身看資料(文檔和博客)而後寫本身的一個小應用, 而不是跟着某一個教程從頭至尾過一遍, 雖然不得不認可, 後者學起來的感受很爽, 並且也更清晰. 可是很差的地方就是技術棧不徹底匹配的時候就會很頭疼...)
下面是目錄:css

  1. 前端 (包括react, redux, css-module等)html

  2. 後端 (包括express, mongodb)前端

  3. 先後端 (包括fetch, jwt)node

  4. 其餘 (包括webpack, 優化等)react

下面直接進入正題.webpack


第一部分 前端

1, react

react的學習根據官方文檔, 主要是理解一下幾個方面的內容:git

  1. 構建模塊的方法. 用了推薦es6class的方法而非createClass.es6

  2. 如何導入導出模塊. es6importexport.github

  3. jsx的編寫. 不是必要的, 官網推薦. 感受其中用上es6模板字符串, map方法會很方便不少~web

  4. props, state, refs的相關概念以及使用. 單向數據流中, 父組件給子組件傳遞數據經過props, 子組件給父組件傳遞數據用回調函數. 後者的實現是經過父組件把一個函數傳到子組件中, 這個函數裏面有能夠有this.setState(收到子組件的數據後馬上渲染), 而後子組件調用傳進來的函數, 經過這個函數把參數傳給父組件.

  5. 掌握connect組件的使用方法. 把state數據和dispatch傳進組件中.

  6. 生命週期. 在這個博客SPA應用裏用了componentDidMountcomponentWillReceiveProps, 前者可用於初始化的渲染以及異步請求的發起, 後者用於接收到新的數據時的再次渲染, 把異步的結果渲染出來. 所以一個組件(涉及到異步)是這樣工做的: 調用組件 -> 組件渲染以前發起異步請求 -> 第一次渲染,沒有數據的頁面 -> 接收到異步發回來的數據 -> 從新渲染, 有數據的頁面. 代碼以下, 基本也是按照這種數據流向的方法來的(不知道是否是最好的方案, 可是感受很方便).

    class Archive extends React.Component {
        constructor(props) {
        super(props);
        this.displayName = 'Archive';
        this.state = {
          articles: []
        }
      }
    
      componentDidMount() {
        this.props.actions.getTitles({
          type: "ARCHIVE"
        })
      }
    
      componentWillReceiveProps(nextProps) {
        this.setState({
          articles: nextProps.getTitles.articles
        })
      }
    
      render() { 
        return (
          <div className={style.archive}>
            {/*這裏是相關的渲染articles的操做, 注意要把[]的狀況也考慮到*/}
          </div>
        )
    }

    }

    export default Archive

配合好setState和生命週期, 運用好父子組件之間的數據傳遞可以很好地完成各類異步渲染.

2, redux

理解redux主要是要理解action, reducer, middleware等概念. 我的感受redux官方文檔簡直精彩, 例子也很豐富, 很是值得學習. 這個SPA博客裏的action大部分是爲了ajax獲取後端數據服務的. 下面選取了其中的一組, 功能是獲取單獨的文章. 對應不一樣相應狀態有不一樣的action. 這樣就能夠把異步的每個狀態記錄下來, 使得數據的流向更加清晰. 具體有關異步請求的相關的內容能夠看個人上一篇文章.

export const singleRequest = () => {
  return {
    type: SINGLE_REQUEST
  }
}

export const singleSuccess = (article) => {
  return {
    type: SINGLE_SUCCESS,
    article: article
  }
}

export const singleFailure = () => {
  return {
    type: SINGLE_FAILURE
  }
}

export const getSingle = (day, title) => {
  return dispatch => {
    dispatch(singleRequest())
    return fetch('/api/single', {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Accept": "application/json" 
      },
      body: JSON.stringify({
        day: day,
        title: title
      })
    })
    .then(checkHttpStatus)
    .then(res => res.json())
    .then(res => {
      if(res.ok) {
        dispatch(singleSuccess(res.article))
      } else {
        dispatch(singleFailure())
      }
    })
  }
}

至於在reducer中, 初始化state用了幾個標識. 好比下面的例子中, 初始化的reducer state 包含了isFetching, isFetched, fetchFailure這些標誌異步進行的當前狀態的信息. 傳入props以後能夠很方便地進行異步請求前後的設置. 比方說一個異步要在另外一個異步以後, 就能夠經過讀取這幾個數值完成. (第二個異步必定要在第一個的isFetchedtrue的時候才能發起)

const initialState = {
  isFetching: false,
  isFetched: false,
  fetchFailure: false,
  articles: [],
  count: 1
}

在整個應用中須要用到中間件, 在應用中用了thunk還有logger.

3, css-modules

在博客應用中css的引入用的是css-modules, 阮一峯大神的這篇文章講得算是完整了, 感興趣能夠看一下~ 固然有些部分也仍是用了css in js的方法, 直接把css寫到js裏面, 主要是考慮到一些操做的方便, 好比點擊以後某一個標籤display改變之類的.


第二部分 後端

說來慚愧, 後端大部分都是"抄"的, 以前看的一個教程是用expressejs寫的博客應用, 然後端的操做大部分都比較接近. 主要就是根據接口路由處理數據, 發送數據, 經過數據庫api(這裏是mongodb)讀取數據庫數據. 因此最後寫出來的和我本來看的那個教程有很大的類似之處. 我看的教程是這一個, 很是棒, 感謝做者!!>o<!!

1, express (nodejs)

關於express我的感受比較重要的是處理配置以及路由兩個方面的問題.
前者須要靠本身慢慢摸索, 好比要處理json須要用到bodyParser模塊, webpack一些中間件的配置等等, 能夠拿redux官網還有上面提到的教程來參考一下.
後者主要是要了解express提供的各類方法, 以及一些有關res和req的相關操做等等.

2, mongodb

有關數據庫的操做我也是參考上面的教程的...(oh..)基本對數據庫的增刪查改要掌握. 更多有關mongoapi原理等能夠去看官網介紹.

3, 不足之處

因爲目標不是專業後端, 因此後端作得比較粗糙. 不足之處有不少, 好比沒有擁抱es6(明明前端已經擁抱), 好比還在若無其事地寫着臭名昭著的回調金字塔等等等. nodejs須要增強.


第三部分 先後端

1, 登陸 (JSON Web Token)

有關登陸和登出開始找了不少相關的實現方法, 在這篇文章的推薦下看了JWT實現方式. 簡單來講就是前端把密碼post到後端, 後端生成一個token而後發送到前端去. 前端把收到的token保存在localStorage中. 每次須要獲取一些保密的信息或者須要作一些修改的時候, 把這個token寫在請求的headers裏. 後端收到數據以後就會先驗證一下token是否正確, 正確才容許操做.

headers: {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authorization": `Bearer ${token}`
      }

2,fetch (獲取數據)

關於先後端交互這一點能夠參考我寫的上一篇文章. 後端把api暴露出來給前端, 前端經過ajax進行數據的交互, 並把獲取到的數據渲染出來. 操做上沒有難度, 只是要注意異步操做中redux要用中間件.
有關中間件還要去看點高階函數的基礎知識, 否則沒法正確理解.


第四部分 其餘

1,webpack

沒有怎麼認真地看webpack的東西, 都是順手操起來直接用的...
說實話, 第一次開始看chromedevtoolnetwork的時候, 我被嚇得不輕...一個bundle文件5m大, PC端打開以後真的是不忍直視. 後來上網找了一些webpack打包優化的方向, 在這裏記錄一下:

  1. webpack的config文件裏面不能有cheap-module-eval-source-map之類的devtool, 真的很大很大...

  2. plugin若是不是必要的話也請刪去吧. 不過有兩個plugin能夠在生產環境中用一下, 第一個是UglifyJsPlugin, 用於壓縮文件. 第二個是CommonsChunkPlugin, 這個具體下一點解釋.

  3. 適當分塊. CommonsChunkPlugin用於把bundle分塊, 把能夠放在緩存的, 經常使用的, 體積比較大的壓縮到vendor裏面(好比react等). 後來又把babel-polyfill分開另外加載了. 以前有看到code split, 就是直到須要用到該ui組件的時候纔去加載, 想法好像不錯, 不過感受改動會比較大因此最後沒有作.

最後的文件大小其實也仍是不小, 可是有了很好的改善. 關於前端優化也是一個重要的話題.

2,markdown

博客應用寫做用的是markdown. 本來想找一個現成的, 可是死活找不到合適的...最後直接用marked強行假裝markdown編輯器...其實這很不安全, 但目前也沒有什麼辦法...(draft.js貌似能夠?)


總結

整體來講, 這個博客其實實現起來沒有特別高的難度, 可是對於初學者來講感受真的挺不容易的. 以前聽過這樣一句話--不要同時學幾樣東西, 其實還真的有點道理...可是對於一些最佳實踐, 自己就要結合在一塊兒才能發揮其最大的做用, 不一塊兒學又怎麼能行呢?(所以就陷入了大坑).
這個博客不完善的地方太多了, 特別是有關安全方面的問題.不過如今仍是先關注着前端吧.

但願這篇文章可以給你一點點幫助.
最後上代碼博客代碼

(本人是初學者, 若是有什麼說得不對, 很差的地方歡迎指出來, 感激涕零!~互相學習!~)

相關文章
相關標籤/搜索