基於webpack4搭建的react項目框架

介紹

框架介紹,使用webpac構建的react單頁面應用,集成antd。使用webpack-dev-server啓動本地服務,加入熱更新便於開發調試。使用bundle-loader進行代碼切割懶加載
手動搭建,不使用cli,大量註釋適合初學者對webpack的理解學習,對react項目的深刻了解css

啓動

git clone https://gitee.com/wjj0720/react-demo.git
  cd react-demo
  yarn
  yarn start

打包

yarn build

目錄結構

+node_modules
  -src
    +asset
    +Layout
    +pages
    +redux
    +utils
    +app.js
    +index.html
    +index.js
  .babelrc 
  package.json 
  postcss.config.js
  webpack.config.js //webpack 配置

bundle-loader 懶加載使用

// webpack.config.js 配置
  module: {
    rules: [
      {
        test: /\.bundle\.js$/,
        use: {
          loader: 'bundle-loader',
          options: {
            name: '[name]',
            lazy: true
          }
        }
      }
    ]
  }
  // 頁面引入組件
  import Home from "bundle-loader?lazy&name=[name]!./Home";

  // 組件使用 由於組件懶加載 是經過異步的形式引入 因此不能再頁面直接以標籤的形式使用 須要作使用封裝 
  import React, {Component} from 'react'
  import { withRouter } from 'react-router-dom'
  class LazyLoad extends Component {
    state = {
      LoadOver: null
    }
    componentWillMount() {
      this.props.Loading(c => {
        this.setState({
          LoadOver: withRouter(c.default)
        })
      })
    }
  
    render() {
      let {LoadOver} = this.state;
      return (
        LoadOver ? <LoadOver/> : <div>加載動畫</div>
      )
    }
  }
  export default LazyLoad

  // 經過封裝的懶加載組件過分 增長加載動畫
  <LazyLoad Loading={Home} />

路由配置

框架按照模塊劃分,pages文件夾下具備route.js 即爲一個模塊html

// 經過require.context讀取模塊下路由文件
  const files = require.context('./pages', true, /route\.js$/)
  let routers = files.keys().reduce((routers, route) => {
    let router = files(route).default
    return routers.concat(router)
  }, [])

  // 模塊路由文件格式
  import User from "bundle-loader?lazy&name=[name]!./User";
  export default [
    {
      path: '/user',
      component: User
    },
    {
      path: '/user/:id',
      component: User
    }
  ]

redux 使用介紹

// ---------建立 --------
  // 爲了避免免action、reducer 在不一樣文件 來回切換 對象的形式建立

  // createReducer 將書寫格式建立成rudex認識的reducer
  export function createReducer({state: initState, reducer}) {
    return (state = initState, action) => {
      return reducer.hasOwnProperty(action.type) ? reducer[action.type](state, action) : state
    }
  }

  // 建立頁面級別的store
  const User_Info_fetch_Memo = 'User_Info_fetch_Memo'
  const store = {
    // 初始化數據
    state: {
      memo: 9,
      test: 0
    },
    action: {
      async fetchMemo (params) {
        return {
          type: User_Info_fetch_Memo,
          callAPI: {url: 'http://stage-mapi.yimifudao.com/statistics/cc/kpi', params, config: {}},
          payload: params
        }
      },
      ...
    },
    reducer: {
      [User_Info_fetch_Memo] (prevState = {}, {payload}) {
        console.log('reducer--->',payload)
        return {
          ...prevState,
          memo: payload.memo
        }
      },
      ...
    }
  }

  export default createReducer(store)
  export const action = store.action

  // 最終在模塊界別組合 [固然模塊也有公共的數據(見Home模塊下的demo寫法)]
  import {combineReducers} from 'redux'
  import info from './Info/store'
  export default combineReducers({
    info,
    。。。
  })

  // 最終rudex文件夾下的store.js 會去取全部模塊下的store.js  組成一個大的store也就是咱們最終倉庫

  // --------使用------
  // 首先在app.js中將store和app關聯
  import { createStore } from 'redux'
  import { Provider } from 'react-redux'
  // reducer即咱們最終
  import reducer from './redux/store.js'
  // 用戶異步action的中間件
  import middleware from './utils/middleware.js'
  let store = createStore(reducer, middleware)
  <Provider store={store}>
    。。。
  </Provider>


  // 而後組件調用 只須要在組件導出時候 使用connent連接便可
  import React, {Component} from 'react'
  import {connect} from 'react-redux'
  // 從頁面級別的store中導出action
  import {action} from './store'

  class Demo extends Component {
    const handle = () => {
      // 觸發action
      this.props.dispatch(action.fetchMemo({}))
    }
    render () {
      console.log(this.props.test)
      return <div onClick={this.handle}>ss</div>
    }
  }
  export default connect(state => ({
    test: state.user.memo.test
  }) )(demo)

關於redux中間件

// 與其說redux中間件不如說action中間件
  // 中間件執行時機  即每一個action觸發以前執行

  // 
  import { applyMiddleware } from 'redux'
  import fetchProxy from './fetchProxy';

  // 中間件 是三個嵌套的函數 第一個入參爲整個store 第二個爲store.dispatch 第三個爲本次觸發的action 
  // 簡單封裝的中間件  沒有對請求失敗作過多處理 目的在與項錯誤處理機制給到頁面處理
  const middleware = ({getState}) => next => async action => {
    // 此時的aciton尚未被執行 
    const {type, callAPI, payload} = await action
    // 沒有異步請求直接返回action
    if (!callAPI) return next({type, payload})
    // 請求數據
    const res = await fetchProxy(callAPI)
    // 請求數據失敗 提示
    if (res.status !== 200)  return console.log('網絡錯誤!')
    // 請求成功 返回data
    return next({type, payload: res.data})
  }
  export default applyMiddleware(middleware)
相關文章
相關標籤/搜索