博客重構記錄 一 數據框架搭建

前言

以前已經把博客作好了,因爲用了antd實現,界面感受很不完美,並且也有一些bug,最近在找工做,投簡歷,只獲得了一次的面試機會,面試完感受本身作得挺很差的,因而想着再努力一點,繼續作多點項目,因爲博客以前完成得很很差,因此打算把博客重構一遍。前端

  • 目標
    • 使用全新的 UI 界面,界面參考
    • 中前臺分離
      • 我備案的域名在審覈,這幾天應該就下來,下來以後部署好 HTTPS,前臺 80,443 端口只負責靜態頁面的展現,再也不涉及登陸操做,博客內容管理統一放在中臺管理
    • 前臺添加 添加 github 登陸接口
    • 增長評論、點贊功能。
    • 暫時須要實現這三個功能,再多的功能之後想到再添加

博客項目數據操做框架搭建框架搭建

  • 項目使用的庫
    • 數據管理 redux
      • 異步方案 redux-saga
      • redux流程: 組件派發action,reducer接收 action改變state,state改變視圖更新
      • redux組成
        • store:存儲應用中全部的狀態,在 react中,一般使用react-redux提供的提供的Provider組件用做跟組件,提供應用所須要的store
          • 建立:使用 redux提供的 createStore方法建立 store
          • createStore方法接收三個參數
            • reducer:必選,因爲應用中可能存在多個 reducer管理不一樣的信息,一般狀況下,createStore方法中的 reducer都是由combineReducer方法建立返回的.
          • preloadedState:可選,應用中最初的的狀態,能夠預先定義一些不須要經過數據請求就能夠展現使用的信息.
          • enhancer:可選,顧名思義,用於加強 redux的能力,使用 redux提供的compose方法生成,``compose方法內使用applyMiddleware`把使用到的中間件用做加強子.
        • action:把數據從應用傳到 store的載體,store數據的惟一來源,action本質是一個 JavaScript對象,必須包含type屬性,其他能夠根據實際狀況須要增長,大部分狀況下,其他屬性都命名爲 payload.由dispatch派發,格式dispatch({type:any,payload?})
        • reducer:接收dispatch派發過來的 action,根據action.type的不一樣肯定如何使用action.payload來到更新 state
    • redux-saga:用於在派發 action前,從有反作用(effect)的方法生成純淨的 action=> 即一個typepayload的內容都是肯定對象{type:xxx,payload:xxx},全部異步中間件的做用都是如此.
      • redux-saga流程:
        1. 建立一個異步發送異步請求的生成器函數 function* getAsync
          • 在函數內部使用 call/fork方法調用已經編寫好的異步請求函數,也能夠不使用call/fork方法,可是異步獲取數據的業務邏輯就須要寫在getAsync內部.
          • 異步請求成功,使用put方法派發成功的 action,並把得到的數據放在action.payload
          • 異步請求失敗,使用put方法派發請求失敗的 action
        2. 建立一個生成器函數watchFetchRequest,內部使用takeEvery函數,takeEvery函數的做用是用於接收 action,在不使用redux-saga時,能接收 action的只有 reducer
          • takeEvery函數接收兩個參數
            • type:行爲標識=>標明action的類型
          • 執行函數:經過第一個參數的標明的type,只要傳入的type是相應類型的,就執行該對應方法
        3. 可選:saga.js文件存在多個不一樣的異步請求,建立一個生成器函數xxxSaga,內部使用all方法,同時執行多個執行異步請求的生成器函數,因爲call方法會阻塞瀏覽器進程,爲了讓異步請求不阻塞,all方法內被執行的watchFetchRequest一類的方法使用fork方法調用,使其不會阻塞瀏覽器進程
      • 最後,導出由使用takeEvery / all生成的 xxSaga函數,傳遞給 sagaMiddleWare
    • 流程都梳理好了,那就開始建立文件,書寫代碼
      1. 建立行爲標識以及數據類型src/store/article/types.ts 1.定義數據的類型
        import { Action } from 'redux'
         // 根據從服務器返回的 article 信息定義 Article 類型
         export interface Article {
           readonly _id: string
           readonly content: string
           readonly summary: string
           readonly category: Category
           readonly viewCount: number
           readonly createdAt: string
           readonly updatedAt: string
         }
         // 根據從服務器返回 category 的信息定義 Category
         export interface Category {
           readonly _id: string
           readonly name: string
           readonly articleCount: number
           readonly createdAt: string
           readonly updatedAt: string
         }
         
         // 定義 store 中存儲的 Article 中狀態信息
         export interface ArticleState {
           data: Article[]
           loading: boolean
           error?: any
         }
        
         // 定義行爲標識
         export const FETCH_REQUEST = 'FETCH_REQUEST'
         export type FETCH_REQUEST = typeof FETCH_REQUEST
        
         export const FETCH_SUCCESS = 'FETCH_SUCCESS'
         export type FETCH_SUCCESS = typeof FETCH_SUCCESS
        
         export const FETCH_ERROR = 'FETCH_ERROR'
         export type FETCH_ERROR = typeof FETCH_ERROR
         
         // 定義行爲
         export interface fetchRequestAction extends Action {
           type: FETCH_REQUEST
         }
        
         export interface fetchSuccessAction extends Action {
           type: FETCH_SUCCESS
           payload: Article[]
         }
        
         export interface fetchErrorAction extends Action {
           type: FETCH_ERROR
           message: string
         }
         
         // 把上面全部的行爲統一使用建立聯合類型 ArticleAction
         export type ArticleAction = fetchRequestAction | fetchSuccessAction | fetchErrorAction
        複製代碼
      2. src/store/article/action.ts
        1. 定義 actionCreator
        import { ArticleAction, FETCH_REQUEST, FETCH_SUCCESS, FETCH_ERROR } from './types'
        
          // 發送請求,向 reducer 傳遞正在發送請求這一消息,把 state設置爲 true 改成 true
          export function fetchRequest(): ArticleAction {
            return {
              type: FETCH_REQUEST
            }
          }
        
          // 請求成功,向 reducer 傳遞請求成功後返回的數據
          export function fetchSuccess(data:any): ArticleAction {
            return {
              type: FETCH_SUCCESS,
              payload: data
            }
          }
        
          // 請求失敗向 reducer 傳遞失敗的錯誤信息
          export function fetchError(message:string): ArticleAction {
            return {
              type: FETCH_ERROR,
              message
            }
          }
        複製代碼
      3. src/store/article/saga.ts
        1. 建立 saga
        import { call, all, fork, put, takeEvery } from 'redux-saga/effects'
         import { FETCH_REQUEST } from './types'
         import { fetchArticles } from '../../api/article'
         import { fetchError, fetchSuccess } from './action'
        
         // 建立異步邏輯處理函數 getArticles
         function* getArticles() {
           try {
             // 使用 call 方法調用從 api 中傳遞過來的 fetchArticle,根據返回結果使用put 方法派發不一樣的 action
             const res = yield call(fetchArticles)
             res.error ? yield put(fetchError(res.error)) : yield put(fetchSuccess(res.data))
           } catch (e) {
             let errorResult = e instanceof Error && e.stack ? e.stack : '不知名錯誤'
             yield put(fetchError(errorResult))
           }
         }
        
         // 使用 takeEvery 方法捕獲從應用派發的action.type,調用相對應的方法 getArticles 
         function* watchFetchRequest() {
           yield takeEvery(FETCH_REQUEST, getArticles)
         }
         
         // 爲了方便之後應用的擴展,使用 all方法整合當前文件由 takeEvery 捕獲的全部全部 dispatch 做爲 當前類型的 saga
         export default function* saga() {
           yield all([fork(watchFetchRequest)])
         }
        複製代碼
      4. src/store/article/reducer.ts
        1. 定義 store 的初始狀態及編寫 reducer 函數
        import { ArticleAction, ArticleState, FETCH_REQUEST, FETCH_SUCCESS, FETCH_ERROR } from './types'
           import { Reducer } from 'redux';
        
           // 初始狀態
           const initState: ArticleState = {
             data: [],
             loading: false,
             error:undefined
           } 
        
           const  articleReducer: Reducer<ArticleState, ArticleAction> = (state= initState, action) => {
             switch (action.type) {
               case FETCH_REQUEST:
                 // 發送請求,將 loading 狀態設置爲 true
                 return {...state,loading:true}
               case FETCH_SUCCESS:
                 // 請求成功,將 loading 狀態設置爲 false,同時使用從服務器中返回的數據更新 state
                 const data = action.payload
                 return {...state,loading:false,data}
               case FETCH_ERROR:
                 // 請求失敗,將 loading 狀態設置爲 false,同時把錯誤信息更新到 state 上
                 return {...state,error:action.message,loading:false}
               default:
               return state
             }
           }
        
           export default articleReducer
        複製代碼
      5. src/store/index.ts
        import { connectRouter, RouterState } from 'connected-react-router'
        import { combineReducers } from 'redux'
        import { History } from 'history'
        import {all,fork} from 'redux-saga/effects'
        
        // 導入各個文件的 reducer saga,狀態類型
        import articleSaga from './article/saga'
        import articleReducer from './article/reducer'
        import { ArticleState } from './article/types'
        
        // 定義應用的 store 中的 多個 reducers 的類型
        export interface ApplicationState {
          article: ArticleState
          router: RouterState
        }
        
        // 使用 combineReducers 建立 rootReducer
        export const createRootReducer = (history: History) =>
          combineReducers({
            article: articleReducer,
            router: connectRouter(history)
          })
        
        // 使用 all 方法建立 rootSaga
        export function* rootSaga() {
          yield all([fork(articleSaga)])
        }
        
        複製代碼
      6. ```/src/configureStore.ts`
        1. redux進行最後配置
        import { Store, createStore, applyMiddleware, compose } from 'redux'
         import  createSagaMiddleware  from 'redux-saga'
         // 使用 使用 router-middle-ware 把瀏覽器 history 掛載到 redux 容器上
         import { routerMiddleware } from 'connected-react-router'
         // 指明傳遞給 configureStore 的 history 參數爲 History 類型
         import { History } from 'history'
         // 導入狀態接口,以及通過聯合後的 reducers/sagas
         import { ApplicationState, createRootReducer, rootSaga } from './store'
        
        
         export default function configureStore(history: History,initialState: ApplicationState): Store<ApplicationState> {
           // 建立saga 中間件
           const sagaMiddleware = createSagaMiddleware()
           // 使用 rootReducer/rootSaga,建立 store, 容器的初始狀態(initialState)會在應用的入口傳入
           const store = createStore(
             createRootReducer(history),
             initialState,
             compose(applyMiddleware(routerMiddleware(history), sagaMiddleware))
           )
           sagaMiddleware.run(rootSaga)
           return store
         }
        複製代碼
      7. src/Main.tsx
        import React from 'react';
           import {Store} from 'redux';
           import { ApplicationState } from './store';
           import { Provider } from 'react-redux';
           import { ConnectedRouter } from 'connected-react-router';
           import {History} from 'history'
        
           // Main 組件須要傳入的屬性分別爲由 redux 建立的 store,由瀏覽器歷史 history
           interface MainProps {
             store: Store<ApplicationState>
             history:History
           }
        
           // Main組件: 提供應所需用 store,和 router 的容器
           const Main: React.FC<MainProps> = ({ store, history }) => {
             return (
               <Provider store={store}>
                 <ConnectedRouter history={history}>
                 </ConnectedRouter>
             </Provider>
             );
           }
        
           export default Main;
        複製代碼
      8. src/index.tsx
        1. 應用程序主入口
        import React from 'react'
         import ReactDOM from 'react-dom'
         import { createBrowserHistory } from 'history'
         import * as serviceWorker from './serviceWorker'
         import configureStore from './configureStore'
         import Main from './Main'
         import { History } from 'history'
         const initialState = window.INITIAL_REDUX_STATE
        
         const history: History = createBrowserHistory({
           basename: '/'
         })
         const store = configureStore(history, initialState)
        
         ReactDOM.render(<Main store={store} history={history} />, document.getElementById('root'))
         serviceWorker.unregister()
        複製代碼

以上就是就是博客基礎狀態共享的框架搭建和代碼.依據以上的框架,當須要添加新的狀態時,能夠很輕易的添加到對應的文件中,若是有新的 reducer 須要建立,只須要在對應的步驟中加入新的reducer/saga便可react

求職中,若是有須要初級前端的歡迎聯繫,電話/微信同號 13416179124, QQ 264589826git

相關文章
相關標籤/搜索