基于飞冰的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国,此次不一样的是,它带来了更强大的队伍………………

相关文章
相关标签/搜索