基於飛冰的React+redux+saga的後臺管理系統實戰開發(一)

前言

最近因爲公司需求,想要快速開發一個後臺管理系統,上頭看上了飛冰可以快速搭建UI界面,可是基於react開發的,本人以前是用react+mobx開發了個後臺管理系統,可是發現主流的仍是react+redux+saga的組合拳。恰好上面把這個項目給我來寫了,因而我決定硬着頭皮一邊自學redux和saga嘗試,當時天天早上坐公交的路上不斷看redux和saga的知識,去看了GitHub的幾個react完整項目後,直接用這套主流的組合。vue

飛冰是什麼?

首先介紹下飛冰,飛冰是一套綜合解決方案,用來極速構建中後臺應用,飛冰是個有必定超越,又不重合 Ant.Design 的概念。後者是一個工具箱,而前者是一個成型的產品模板。如圖:react

能夠自由選擇相對應模板,而後組裝。這樣的話,在UI和界面上會省事不少。具體怎麼玩我就不介紹了,官網下載個,本身嘗試下,仍是挺簡單的,很是的組件化和可視化。git

項目結構與數據傳遞

如圖,飛冰構建下來的項目很組件化,我我的喜歡的是,把(redux)數據傳遞寫在父組件頁面上,而後那個子組件須要什麼數據,我只給它傳它須要的數據,若是適合的話,可讓子組件是一個無狀態函數式組件github

關於無狀態函數式組件

引自Levid_GC的翻譯文章【譯】在 React 中擁抱函數——無狀態函數式組件及其重要性vuex

  • 特色

無狀態函數式組件的特色就是沒有this和ref無生命週期方法redux

函數式組件,有時也被稱爲無狀態組件,沒有任何生命週期方法,意味着每次上層組件樹狀態發生變動時它們都會從新渲染,這就是由於缺乏 shouldComponentUpdate 方法致使的。這也一樣意味着您不能定義某些基於組件掛載和卸載的行爲segmentfault

有個誤區就是說:簡單地認爲使用純無狀態函數式組件能夠得到性能上的提高這個觀點是不正確的。相反,當咱們須要處理大量無狀態函數型組件的時候,它的對立觀點倒是正確的。api

項目子組件實例:數組

const TodoListUI = (props)=> {
    return (
        <div>
            <div>
                <Input placeholder="Basic usage" 
                value={props.inputValue}
                style={{width:'300px', margin: '10px',}} 
                onChange={props.handleInputChange}
                />
                <Button type="primary" onClick={props.handleBtnclick}>提交</Button>
                <List
                    style= {{margin: '10px',width:'300px'}}
                    bordered
                    dataSource={props.list}
                    renderItem={(item,index) => (<List.Item 
                    onClick={props.handleItemDel.bind(this,index)}>{item}</List.Item>)}
                />
            </div>
        </div> 
    )
}
//普通組件,是類,有生命週期,比無狀態函數組件性能損耗高些,若只有render函數(只負責渲染),便可用無狀態組件。
複製代碼
  • 那爲什麼要用無狀態函數組件?

使用無狀態函數式組件最大的好處就是它可以將容器型和展現型組件明確區分開來,避免產生大型以及雜亂的組件。bash

來自oNexiaoyao對上面的翻譯文章的評論,我的以爲挺不錯的,能夠做爲一個參考:

我倒以爲官方推薦使用無狀態組件更多的是鼓勵咱們採用組件化的思想,將原來的一個比較大的展現組件逐步拆分紅一個一個小組件,而後再將小組件拆分紅更小的組件,最後大部分組件都是能夠拆成不少個小的無狀態的組件(只提供頁面層的展現),將控制與展現分離,邏輯層次結構更加的清晰。可是這樣就會帶來一個問題:代碼拆到最後是否是會顯得比較繁瑣呢?。固然,這樣的組件化的思想一旦造成,對於代碼結構的組成或者說代碼的複用能力都是一種極大的提高。

固然,用不用都是看實際項目狀況,若是想讓你手上的代碼作個「精緻的豬豬男孩」,能夠考慮。

頁面結構與數據傳遞

貼一個個人某個父組件頁面的代碼

import React, { Component } from 'react';
import BasicTab from './components/BasicTab';
import InfoDisplayTable from './components/InfoDisplayTable';
import UserTable from './components/UserTable';

//如下引入全部關於redux
import { connect } from 'react-redux';
import { compose } from 'redux';
import { bindActionCreators } from 'redux';
import injectReducer from '../../../utils/injectReducer';
import reducer from '../../../redux/Merchant/reducer';
import * as merchantAction from '../../../redux/Merchant/action';

class UserDetail extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  componentDidMount(){
   //...省去部分不相關代碼
    const {actions} = this.props
    actions.userResultDetail({
        '我是請求要的key':'我是請求要的value'
    })
  }

  fndelete =(uuid)=>{
    //...省去部分不相關代碼
  }

  fnupdate=(obj)=>{
    //...省去部分不相關代碼
  }

  fnaccount=(obj)=>{
    //...省去部分不相關代碼
  }

  render() {
    return (
      <div className="user-detail-page">
       {/* 可篩選過濾的用戶類表格 */}
        <UserTable sn = {this.props.state.user}   //'這裏只傳子組件須要的數據和事件'
        fndelete = {(id)=>this.fndelete(id)}
        fnupdate = {(obj)=>this.fnupdate(obj)}
        fnaccount = {(obj)=>this.fnaccount(obj)}
        />
        {/* 基礎 Tab 組件 */}
        <BasicTab data = {this.props.state.list} /> //'這裏只傳子組件須要的數據'
       
      </div>
    );
  }
}


const mapStateToProps = (state) => {
  return { state:state.merchant.detail };
};

const mapDispatchToProps = (dispatch) => ({
  actions: bindActionCreators(merchantAction, dispatch)
});

const withConnect = connect(
  mapStateToProps,
  mapDispatchToProps
);

const withReducer = injectReducer({ key: 'merchant', reducer });

export default compose(
  withReducer,
  withConnect
)(UserDetail);
複製代碼

這是一個完整的父組件頁面,我的喜歡父組件進行數據的請求觸發和處理,子組件就乖乖的拿數據負責渲染就行了,因此我也推薦能夠考慮用無狀態函數組件適當提升下性能。

這樣的明確分工會讓我寫的比較舒服,一旦有關於數據的問題,我會在父組件上先尋找緣由,並且這樣只須要引入一次redux就能夠了。 寫的多了,你一看後臺管理,自動會把這頁面分紅一塊一塊的。

頁面大概是這樣,飛冰自建下來的項目結構仍是比較清晰的,接下來來看下咱們的數據,是怎麼流動的!

單向數據流Redux

引自4 張動圖解釋爲何(何時)使用 Redux

兩張圖很直觀體現了redux的好處。

使用前:

使用後:

單向數據流的統一性和可預測性都大大提升了開發的方便和效率。

關於redux的學習,我的推薦這個GitHub入門徹底理解 redux

redux的教程琳琅滿目,當時我也看了好幾個,剛開始入門以爲好複雜啊,各類api和概念整得我一臉懵逼,跟vuex比起來,好像難了不少。 通過一輪的學習,我以爲其實只要知道redux的原理和核心思想,其它的,都只是輔助罷了。

redux的核心即是:單向數據流

記住三個關鍵詞: StoreActionReducer

有個故事是這樣的:

有個叫button的帶領了一羣戰士侵佔了一個store國的邊境的土地,特地放走了個俘虜,還讓他帶話說:「winter is coming」。

俘虜連忙跑到Store的首都找到了Store的國王,國王知道了此事,開了個緊急會議,問軍師Action應該怎麼辦。

Action聽到了winter is coming這句話的時候,顫抖了下,並說:「他們真的來了,咱們要認真對待這件事了,我建議排上咱們最好的騎士Reducer帶領三千精兵去奪回咱們的邊境。」

因而傳來Reducer,這個Reducer人狠話很少,上到會議當聽到winter is coming時候,只說了兩個詞:「where和how! 」

話音未落,reducer則帶上兵,走上討伐之路。

過了不久,Store國便傳來Reducer討伐成功的喜訊,收復邊境

這個故事轉換成redux,是這樣的:

在store的環境下,button觸發了事件,而且dispatch(帶話),action其實就是一個會文不會武(一個對象,僅此而已)的軍師,當它收到那句話 的時候,它就明白是什麼狀況,因而讓相對應的reducer去處理,reducer也是只接收兩個參數,根據state提供位置來修改,根據action的type來進行相對應的sate修改操做。

Store

Store,惟一的數據管理者,貫穿整個應用。

Store是Redux中數據的統一存儲,維護着state的全部內容,因此Store的主要功能就是:

  • 維護應用的state內容

  • 提供getState()方法獲取 state

  • 提供dispatch(action)方法更新 state

  • 提供subscribe(listener)方法註冊監聽器

看到Store提供的方法,就能夠把Action、Reducer和Store聯繫在一塊兒了:

Store經過dispatch(action)方法來接收不一樣的Action, 根據Action對象的type和數據信息,Store對象能夠經過Reducer函數來更新state的內容。

Action

Action是一個對象,用來表明全部會引發狀態(state)變化的行爲。 只描述行爲信息,(一個列表,按照個人表單來幹事)。

必須包含type這個屬性,reducer將根據這個屬性值來對store進行相應的處理。除此以外的屬性,就是進行這個操做須要的數據。

假如咱們要實現一個任務管理系統,那麼添加任務的Action對象就會是下面的形式:

{
    type: 'ADD_TASK',
    name: 'Read ES6 spec',
    category: 'Reading'
}
複製代碼

Reducer

Action對象僅僅是描述了行爲的相關信息,至於如何經過特定的行爲來更新state,就須要看看Reducer了。 是個函數。

接受兩個參數:要修改的數據(state)action對象。根據action.type來決定採用的操做,對state進行修改,最後返回新的state

最簡單的描述就是: Reducer是一個函數 該函數接收兩個參數,一箇舊的狀態previousState和一個Action對象 返回一個新的狀態newState

以上,是redux的核心內容,若是你知道它的原理是如此,接下來的只有那些api的改變了,萬變不離其宗。

小結

以上,介紹了飛冰是什麼和我的項目的頁面結構,還有redux的簡單描述。 本人也是在學習中,如有大神發現錯誤,還請多多指教。

過了一段時間,button又再一次入侵store國,此次不一樣的是,它帶來了更強大的隊伍………………

相關文章
相關標籤/搜索