concent

concent

  • Docs
  • API
  • ChangeLog
  • GitHub

›核心概念与功能

序言

  • concent是什么
  • 对比redux和mobx

新手指南

  • 快速开始
  • 渐进式的开发
  • 标准化的开发

核心概念与功能

  • 模块
  • 组件
  • reducer
  • 调试

生态与周边

  • react-router-concent
  • concent-plugin-loading

精彩示例

  • concent-antd-pro

reducer


reducer是什么

我们先复习一下concent的状态广播流程

触发流程

从上可以看出,reducer的定位就是用于返回一个新的片段状态,通常我们写reducer的目的就是要把处理数据的业务逻辑和更新视图的渲染逻辑彻底分来开来,达到ui与业务的彻底解耦。

当我们的工程越来越大的时候,这样关注点分离的组织代码方式有利于后期的维护、迭代甚至重构和升级。
业务逻辑会越来越厚但是越来越下沉和稳定,ui逻辑会越变越频繁,

当我们的工程越来越大的时候,这样关注点分离的组织代码方式有利于后期的维护、迭代甚至重构和升级。
业务逻辑会越来越厚但是越来越下沉和稳定,ui逻辑会越变越频繁, reducer函数用于书写用户的业务逻辑并返回一个新的片段状态,由dispatch句柄调用并触发,concent会把reducer函数返回的片段状态视为一个新提交的状态去处理,从用户触发reducer函数到视图被更新会经历以下流程
1 用户调用dispatch函数去触发concent调用reducer函数
2 concent找到对应的reducer函数并触发其执行,并收到reducer函数提交的新的片段状态
3 concent分析reducer提交的新的片段状态,存储到store
4 找到关心这份片段状态的其他cc实例,并将其分发到这些实例上触发它们的渲染

从上面的流程图里,我们可以针对dispatch函数总结为如下流程

dispatch 
    |
    |---trigger---> reducer
                        |
                        |---commit new partialState ---> cc core
                                                            |
                                                            |---save to store---> finder
                                                                                      |
                                                                                      |
                                                    ins1,ins2... <--- broadcast to ---|


定义上来说,concent里的reducer函数和redux里的reducer函数的区别很大,使用体验也会比redux要好很多

相同点

我们先列出以下几个主要的相同点

  • 都需要dispatch来触发
  • 都会返回一个新的状态来触发渲染

差异点

差异点如下:

  • redux的reducer函数是纯函数,concent的reducer函数是纯函数可以是任意的函数
// code in foo/reducer.js

export function updateF1(){
}

export async function uploadF1(){
}

export function* trackF1(){  
}

  • redux的需要借助saga等辅助模块来写副作用,concent的reducer函数更符合编程体验,对比redux的reducer或者其他redux wrapper(dva, rematch...)的reducer,concent提供以下巨大的差异性体验

1 书写一个function 就是纯函数
2 书写一个async function 或者 generator 就是副作用函数
3 任何类型的函数返回状态就会触发视图更新
4 函数之间可以相互组合调用,并且直接基于函数签名调用(注意避免死循环)
5 链式调用的reducer可以合并为一次状态更新操作提交给concent

// 推荐把reducer独立的放置在一个文件中,这样reducer函数件可以直接基于函数签名调用
export function updateF1(f1){
  return {f1}
}

export async function handleF1Change(payload, moduleState, ctx){
  await api.uploadF1();

  return {f1:payload};
  // or ctx.dispatch(updateF1, payload);
}

export async function f2(payload, moduleState, ctx){
  //code here
  await ctx.dispatch(handleF1Change, payload);

  // or await ctx.dispatch('handleF1Change', payload)
  //code here

  return {f2:'to be committed'}
}

export async function f3(payload, moduleState, ctx){
  await api.domeSomething();
  await ctx.dispatch(f2);
  return {f3:'f3 to be committed'};
}

关于链式调用的性能优化

class Foo extends Component{
  changeF1 = ()=>{
    this.$$dispatch('f3');
    // 调用f3 --> 调用f2 --> 调用handleF1Change
    //handleF1Change 返回 {f1:payload} 触发更新
    //f2 返回 {f2:'to be committed'} 触发更新
    //f3 返回 {f3:'f3 to be committed'} 触发更新

    this.$$lazyDispatch('f3');
    //lazyDispatch会将调用链上属于同一个模块的所有状态暂存起来
    //直到根函数调用结束(这里即是f3)
    //一次性合并为  {f1:payload, f2:'to be committed', f3:'f3 to be committed'}
    //再提交给concent,触发一次更新!
  }
}

大多数时候,基于dispatch调用触发实时更新是没有问题的,但是提供的lazyDispatch特性,能够让用户既能够保持reducer拥有最小的业务逻辑单元和更新粒度,又能够对性能有极度追求时避免不必要的多次更新

← 组件调试 →
  • reducer是什么
  • 相同点
  • 差异点
Copyright © 2019 concentjs.org