React+Redux-Saga+Seamless-Immutable+Reduxsauce后台系统搭建之路(三)

Better Practice

1 .不要改变服务器返回的数据

比如服务器返回一个星期信息,格式为:“0,1,2,3,4,5,6”,代表周日、周一、周二、周三、周四、周五、周六,如果为了方便显示,在把数据存到state里面的时候就改变了它的数据,直接改成了周日、周一、周二、周三、周四、周五、周六,那么如果后面需要再次使用这个数据的时候,很难恢复到它最原始的模样了,这是一件吃力不讨好的事情,所以不要改变服务器返回的数据的格式,把展示格式的任务交给view层来做。

2. MVC

这样一个架构其实很明显地将代码分成了MVC层,理论上来说我们可以把所有的组件都做成无状态组件,这里是View层,把saga作为Controller层,reducer作为Module层。
这样我们整个页面的逻辑都放到了Controller层来实现了,页面与页面之间的逻辑不会经常有重合的地方,所以我认为Controller层的每一个函数可以用组件的功能实现来区分。这样页面中用到的所有相同组件都可以用一个方法来管理。
比如这样一个列表:上面有筛选条件,下面是可翻页的表格。
这种列表出现的频率是非常高的,上面是请求参数,现在展示一个列表,同时这个列表是可以翻页的。输入一些搜索条件并点查询翻页要清零,翻页时要保存搜索条件,再根据后端返回的数据将页码传给表格等一系列复杂逻辑,如果一个功能有十个这样的表格,那这样的逻辑就要重复十次。如果我们把这些逻辑都统一到一个saga里,只通过参数中的status来区分数据,这个status反映到state中就是一个结点(稍后会讲到),可以根据结点的名字来区分不同的表格。

export function* queryListData() {
  while (true) {
    const action = yield take(sagaTypes.QUERY_LIST_DATA)
    const { payload } = action
    const state = yield select()
    let { status, filterParams, pagination } = payload
    let defaultFilterParams = {}
    let params = {}
    let defaultPagination = {
      perpage: 10,
      pageSize: 10,
      curpage: 1,
      current: 1,
      total: 0
    }
    if (state.detail.list[status]) {
      defaultFilterParams = state.detail.list[status].filterParams
      // defaultPagination = state.detail.list[status].pagination
    }
    if (pagination && pagination.pageSize) {
      pagination.perpage = pagination.pageSize
    }
    if (pagination && pagination.current) {
      pagination.curpage = pagination.current
    }
    filterParams = {
      ...defaultFilterParams,
      ...filterParams
    }
    pagination = {
      ...defaultPagination,
      ...pagination
    }
    params = {
      ...filterParams,
      ...pagination,
      type: 'page'
    }
    yield put({
      type: types.SET_IN,
      payload: { path: ['list', status, 'filterParams'], value: filterParams }
    })
    yield put({
      type: sagaTypes.QUERY_DATA,
      payload: {
        status: payload.status,
        params
      }
    })
  }
}

3. 状态树的设计

归根结底,我的设计就是组件和数据是一一对应的关系,每个组件自己接入想要的数据,然后抽出公共的方法,这样的来代码结构会非常清晰,state树也只要稍加解释就可以让所有人都能明白其含义,下面是我的state树:


总览.png

远端数据.png

表格.png

模态框.png

4. 流程控制

在项目初始化的时候,我的做法是把能load的数据全部都load进来,通过saga可以通过fork无阻塞的执行这些操作,但是组件已经全部无状态化了,load数据之后会改变state,又会重新执行一些这个函数组件,又会重新load数据...无限循环。
saga有一个非常好的功能,监听未来的 action,具体的使用方法是这样的:

// 这是一个load全部数据的函数
export function* watchInit() {
  while (true) {
    const action = yield take(sagaTypes.INIT)
    ....拉取远端数据的代码
    yield take(sagaTypes.CLEAR)
    ...一些后续操作
  }
}

就是如果发起了一个type为sagaTypes.INIT的action,在没有发起type为sagaTypes.CLEAR的action之前,watchInit将不再执行。我将之称为锁,这样就在无状态组件中模拟实现了componentDidMount里拉数据的过程。但是这种做法的优点在于,试想你需要实现一个功能,有N个页面,每一个页面都需要依赖远端数据,又必须要在每一个页面随时可以点击刷新。如果我们在每一个子页面的componentDidMount方法里都拉一遍数据,那么每进入一个页面中的时候势必会重新拉一遍数据。而saga的实现方法可以做到只要不解锁,就不会重新拉数据,也就是说,虽然每一个页面都会发起sagaTypes.INIT的action,但是只要流程没有走完,就只会拉取一次数据。

5. 总结

if you trade something off, make sure you get something in return. 刚开始使用这一套架构的时候,我也走了很多弯路,因为这样一套工具使用起来,实现一个功能的时候,往往需要修改三个文件,会导致代码量激增。后来总结出来这样一套模式以后,不仅减少了我90%的代码量,而且我相信这样的模式是可以用于任何一个后台页面的。模式一旦确定下来,这样就只剩下很多重复性的工作,那么是不是可以做一个自动生成页面的工具呢?这就是tita。

REFRENCE:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容