述职

86次阅读

共计 3168 个字符,预计需要花费 8 分钟才能阅读完成。

述职分享 – 刘睿敏

主要工作成果

DDP:react/redux-thunk/koa(ssr)

  • 是什么:需求管理平台(需求的创建 -> 评审 -> 开发
  • 用户:产品 / 运营 / 技术 / 大佬 everbody
  • 价值:

    • 解决需求来源不统一(lean/wiki/ 运营直接 d -chat 等等方式提需求等
    • 出现问题,快速准确定责(无法快速且准确的确定需求来源方和需求 owner
  • http://ddp-test.intra.xiaojuk…

把脉:react/typescript/mobx

  • 是什么:滴滴云端诊断分析服务平台,帮助快速发现与定位问题
  • 用户:客服 /RD
  • 价值:其他业务方把原始的 trace 数据接入到把脉,把脉在原始数据的基础上提供界面,帮助快速发现与定位问题
  • http://bamai.xiaojukeji.com/n…

主要工作分享:ddp 前端配置化方案

配置化背景:

一开始 ddp 是一个老老实实的应用,只有网约车一条业务线在用,很多逻辑都硬编码在前端,随后 ERP 想要接入,接入 erp 时,就发现很多问题!!!

  • 业务线有不同的业务需求
    解决方案:前端硬编码 / 大量的 if…else… 逻辑,造成代码冗余,难以维护,可读性查
不同业务方向下,又有不用角色,对应的文案 / 字段 / 字段类型都不同
const isERP = [3,4].includes(Number(sponsor))
const options = detail.type == 1?STATUS[5]:STATUS[detail.sponsor];
tatusOptions={options || STATUS[2] || []}

同一个字段,在不同页面,fetch 需要获取展示不一样的数据
const isShowAllPmTeams = window.location.pathname.indexOf('search') !== -1 || window.location.pathname.indexOf('mine') !== -1
pmTeamsOptions = (isShowAllPmTeams ? searchPmTeamList : pmTeamList) || []

设计原则:

  • 数据驱动页面

    • 页面 json 配置化,组件布局和组件属性均为数据的一部分
    • 写通用的配置化逻辑,在加载页面的时候拉取配置数据,动态生成页面
  • 组件化

    • 组件父子化:便于定制和扩展

      • 父组件本质是一个容器组件(container)。在内部定义了渲染出子组件排列的规则。同时也承担了通用(子组件的表现)的规则(比如子组件布局 & 数据处理 & 报错 & 提示信息处理等)
      • 在父组件中需要定义 component Map 映射,实现一套组件映射关系。
      • 子组件是纯 component, 没有额外的适配逻辑。便于普通 react 组件接入
    • 组件和页面剥离,功能解耦

      • 可复用的基础组件库:快速编辑组件库 / 表单组件库(相似的 props)
      • 业务强耦合的业务组件库:便于页面布局(差异性)
  • 功能插件化

    • 页面功能都 基于事件。页面整个设计模式用了监听者模式。把各种行为操作都通过事件。在组件中定义。然后在页面中监听并补充业务逻辑。
    • 通用的功能默认内置到基础插件,注入默认功能,同时可插拔
    // change 的时候对外暴露 change 事件。同时暴露改子组件相关属性。到页面的部分去处理业务逻辑
    
  • 组件和页面功能易于扩展

    • 组件扩展。通过增加子组件,或者包装子组件 HOC
    • 页面扩展。通过增加插件,实现特定场景的业务功能

在可配置页面里面,我认为要解决的是三个核心问题:

  • 页面布局和样式

    布局:

    • 整个页面被认为是一个树形结构,由不同的组件构成
    • 组件由组件构成,它们是递归构建的,直到最小的组件,这一类的组件逻辑上将无法再被拆分

样式:

  • 绝不配置任何有关样式的信息(同一种类型的组件,都具有同样的样式)

    • 配置样式会带来配置的急剧复杂化(一个组件的样式,由很多控制选项,而且不同组件之间还会相互影响)
    • 配置样式导致样式修改调整都十分困难(相互影响)
  • 问题:有两个组件,它们除了样式不同以外,都一样,那么怎么办?(实例:标题和内容的快速编辑)

    • 定义一种新的组件?组件类型膨胀的问题 / 无法复用,除了 bug 修两个地方
    • 借鉴 antd,配置每个组件的主题(normal, bold, red)/(big/small/middle)

  • 页面内容——也就是数据

限制

  • 不支持复杂布局
  • 不支持复杂交互

有点

  • 释放前端资源,终于不用切砖了!
  • 节省测试资源,接入新的业务的时候,基本上就是看看配置对不对

场景一:

A 模块使用了 data1, B 模块使用了 data2;A B 模块可以修改对应的 data;这两份 data 结构上不同,但是存在业务上的联系:当 data1 更新后需要 data2 更新;data2 更新同样需要 data1 同步;对应后端的两个不同的 API。

我们整理一下

  • A B 使用两份存在联系的 data
  • 其中一个更新需要另一个更新
  • 两份 data 对应不同的 API 接口
  • A B 对应两个不同的 tab 且可能同时存在

方案一

  • 当其中 B 数据因操作发生更新时,在页面 /action 中刷新 A 模块的数据
class B extends React.Component {handleUpdateData = () => {const { dispatch, queryA, queryB} = props
        dispatch(queryB())
        dispatch(queryA())
    }
}
  • 缺点:

    在模块 B 内调用模块 A 的更新逻辑;但这样逻辑就耦合了,我在模块 A 调用模块 B 方法 在模块 B 调用模块 A 的方法;但很有可能这两个模块是没有其他交互的。这违反了低耦合高内聚的原则
    而且书写 redux 的一个原则就是 不要调用(dispatch)其他模块的 action

方案二:发布 - 订阅事件系统 pubsub.js

模块 B – 使用 PubSub.publish 发送事件

模块 A – 订阅事件 type

通过事件系统做到了两个模块之间的解耦,作为事件发布方只管发布自己的事件。两个模块在事件系统唯一的联系就是事先定义好事件的 type

class B extends React.Component {handleUpdateData = () => {PubSub.publish('queryA',null);
    }
}

class A extends React.Component {componentDidMount(){this.pubsub_token = PubSub.subscribe('queryA', function (topic,message) {dispatch(queryA())
      }.bind(this));
    }
    componentWillUnmount(){PubSub.unsubscribe(this.pubsub_token);
    }
}

场景二:

UI 上属于模块的状态数据,依赖子模块的接口返回

方案:

const mergeInLayout = (model, entities) => ({
  type: types.MERGE_IN_LAYOUT,
  model: model,
  entities: entities
})

dispatch(mergeInLayout('cross-domain-review', { status: result.data.reviewStateName}));

case types.MERGE_IN_LAYOUT:
      const data = state.modulesDetail[action.model] ?
        Object.assign({}, state.modulesDetail[action.model], action.entities)
        : action.entities
      return Object.assign({}, state, {modulesDetail: Object.assign({}, state.modulesDetail, {[action.model]: data }),
      });

// immutable

正文完
 0