React实践 - Component Generator
我们开发一个新产品的时候,通常会先抽象出一些公用的组件,然后通过这些组件来拼装成页面。不知道大家有没有发现,这种开发方式带来的问题是一个团队内经常会有这样的场景: A 已经开发了一个 XX 表格模块,B 要开发一个类似的 YY 表格模块,然后 B 通常是去把 A 的代码 copy 一下,修改一些东西;或者不巧 B 不知道 A 已经开发 XX 表格,然后 B 又得一行行的写一些类似的代码。 造成这种问题的原因简单的说就是:组件抽象的粒度太单一。接下来我们会通过两个例子来讲述问题及我们如何解决这样的问题的。 一个简单的组件 - Switch首先我们看一个简单的
如果使用之前封装的基础组件组件 <Switch className="switch" activeIndex={this.state.activeIndex} onChange={::this.handleSwitchChange} > <SwitchItem>趋势</SwitchItem> <SwitchItem>列表</SwitchItem> </Switch> 这种组件抽象方式(实现省略)好处就是通用性强,但带来一些问题:
于是,我们对这类组件进行了重构,希望让每个组件使用更加简单,只需要关系具体的状态即可。具体的做法就是开发一个 Generator —— export const generateSwitch = (name,options) => { const propTypes = { className: PropTypes.string,activeKey: PropTypes.oneOfType([PropTypes.number,PropTypes.string]),onChange: PropTypes.func.isRequired,}; const Switch = (props) => { ... return ( <span className={classes}> { options.map((entry,index) => ( ... )) } </span> ); }; Switch.propTypes = propTypes; Switch.displayName = name; return Switch; }; export const ASwitch = generateSwitch('ABSwitch',[ { name: 'AA',key: 'a' },{ name: 'BB',key: 'b' },]); export const BSwitch = generateSwitch('CDSwitch',[ { name: 'CC',key: 'c' },{ name: 'DD',key: 'd' },]); 这种做法就可以解决上面说的问题:
更复杂的例子 - 业务模块下面以一个表格业务为例,常见的表格模块如下:
在开发这个模块的时候,虽然每个小区块我们都抽取了相应的组件,如 在这里碰到的一个问题是,我们整个系统是使用 Redux 来管理数据的,整个项目的
每个业务模块会去 首先来看 UI Component 的 Generator: function generateAbcModule({pageName,moduleName}) { const ACTION_PREFIX = `${pageName}/${moduleName}`; const LOAD = ACTION_PREFIX + 'LOAD'; ... function load(url,params,id) { return (dispatch,getState) => { const state = getState(); ... return dispatch({ type: LOAD,.... }); }; } @connect((state,props) => { const moduleState = state[pageName][moduleName]; return { ...moduleState,}; },{ load,}) class AbcModule extends Component { ... } return AbcModule; } 通过代码发现,我们把 接下来我们是 function generateAbcModuleReducer({pageName,moduleName,defaultIndexes}) { const ACTION_PREFIX = `${pageName}/${moduleName}/`; const LOAD = ACTION_PREFIX + 'LOAD'; const initialState = { indexes: defaultIndexes,... }; return function AbcModuleReducer(state = initialState,action) { switch (action.type) { case LOAD: return { ...state,isLoading: true,... }; ... } }; 类似的,reducer Generator 也是通过 总结上面这种使用 Generator 来封装业务模块的方法,能够在一定程度上减少重复代码,加快开发速度,不过如果业务发展的很快,有可能会导致业务模块组件 props 泛滥 的问题。
以上面的排行卡片为例,可变的东西就非常多,相应的就需要很多的 props 来配置,所以我们也需要根据具体的业务来把握是否要进行抽象。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |