跟进公司的这个项目也近1月时间了,大概总结一下。
之前的业务逻辑比较复杂,具体体现在对数据的处理上(组件的新增、删除),由于后端返回的数据没有给出当前模块的子节点,所以每次都需要找它的子模板是什么类型(总之业务逻辑相当复杂我也没理清)。
后面二期加上了子节点模板的字段,这样一来,业务就显得比较清晰了,这里梳理一下整个的业务逻辑与数据的交互流向。
首先要清楚这次的几种组件类型:
标题 Cover
房屋信息 House
导语 Intruduce
段落 Paragraph
part Part
图文 Image
列表 List
Paragraph 只能做父节点 (可包裹除任意其他节点)
Part 既能作为子节点被 Paragraph 包裹,又能包裹 Image 、List
others 只能作为子节点,不可包裹其他节点
1、页面初始化时会在willMount生命周期向后端发请求(调用action中的方法),请求回来数据改变redux中的值,进而渲染整个页面。
具体到这个项目中,返回值是两个,一个是shape(代表模板树,根据这个来渲染整个页面各个组件),一个是content(内容树,根据这个来向其中对应位置填充数据)。
来具体看看这两个数据的结构吧
content:
content是一个对象,里面是对应模块的内容,根据这个在初始化的时候回填内容
shape:
shape也是个对象,但shape.child这个属性值是数组,需要使用这个数组来渲染整个页面,顺序不能变。在shape.child这个数组中,每个值都是一个对象,里面的数据是
anchor:表明他的id,content也会根据每个模块的anchor找到他并且将数据回填进去。
config:根据这个里的值判断是否可删除、排序、新增……以决定是否需要加上这些功能
child:如果是包裹组件就会有这个属性来表明被包裹的组件,值也是对象,带有的字段和shape.child一样
name:表示组件被渲染时的抬头名
type:表示组件的类型,即上述7种类型之一
leaf_template:包裹组件会有这个值,是一个数组,来表示需要新增的子组件的类型和配置(type与config字段)
2、具体是如何渲染页面的呢?因为数据的层层嵌套性,所以组件部分是用递归来渲染。调用getcomponent方法,得到每个组件以及其下的嵌套组件。render的时候将header、sidebar和component组件都渲染出来。
说下getcomponent方法吧(不光index会使用,包裹组件也会再通过它渲染子组件)
在index里给它的参数有:(主要是content和shape两个,也就是template_info, article_detail两个字段,用来渲染组件)
{
name: '',
parent: 'comp_root',
template_parent: 'comp_shape',
shape_id: shapeId,
shape: {
comp_shape: template_info
},
child_template_info: template_info,
template_info,
article_detail,
onChangeCompInfo:this.props.changeTemplateInfo,
onChangeArticleInfo: this.props.changeArticleInfo
}
之后是一个switch case 使用map将child_template_info里每一个子组件遍历,判断每一个模板组件的type,根据type选择相应的组件进行渲染,并将参数作为props传给组件
只看核心代码(省略了部分业务逻辑代码)
function getComponents (opts) {
return (
<div key={parent} id={parent}>
{
child_template_info.map((comp, idx) => {
let template_parent = `${temp_parent}[${idx}]`
let options = {
parent,
template_parent,
info: comp,
...rest
}
return _getComponent(options)
})
}
</div>
)
}
function _getComponent (options) {
let { info, ...rest } = options
const { type, anchor, parent } = info
const componentProps = {
...rest,
...info
}
let component = null
let compKey = `${componentProps.parent}_${anchor}`
switch (type) {
case 'cover':
component = <CoverComp key={compKey} {...componentProps} />
break
case 'introduce':
component = <IntroduceComp key={compKey} {...componentProps} />
break
case 'house':
component = <HouseComp key={compKey} {...componentProps} />
break
case 'image':
component = <ImageComp key={compKey} {...componentProps} />
break
case 'part':
component = <PartComp key={compKey} {...componentProps} />
break
case 'furniture':
component = <ListComp key={compKey} {...componentProps} />
break
case 'paragraph':
component = <ParagraphComp key={compKey} {...componentProps} />
break
}
return component
}
3、接下来就具体分析每一种组件的内部逻辑了
3.1 header 头部模块
3.2 sidebar 侧边导航栏模块
3.3 cover 标题模块
3.4 house 房屋信息模块
3.5 introduce 导语模块
3.6 被paragraph包裹的几组模块
这个里面使用了高阶组件,用来提供新增、删除、排序等方法,或用来改变props里的配置信息,
通过这个项目学习到的:
1、react-redux项目的大致思路与流程,需要reducer和action两个文件,reducer里是初始化的redux数据,action里是定义的一些方法,会随着redux传下去,调用action即可改变redux全局变量(redux改变会diff算法后重新渲染页面)。
一般是将redux数据赋值到根组件(根组件即可通过props得到redux中的值和action的方法),然后一层层props传下去,子组件得到redux的值与action方法,通过调用action方法即可改变全局redux的值
2、react的使用,生命周期、state、props……
3、ES6的很多使用,比如解构赋值的灵活运用、箭头函数……
4、写js的规范,const、let、命名规范……
5、项目的优化是永恒的话题,比如抽离UI组件与业务内容组件,抽离公用样式、使用对象表示法(即表驱动编程)代替ifelse……
6、项目架构,各个文件的组织(比如通用方法,api……)
7、高阶组件的使用,可以包裹组件,通过props给组件加上一些方法
8、antd的使用以及如何二次封装antd组件。要点是改变自己需要改变的方法,并且不要忘了将原来的方法透传进去。
9、less以及css modules的使用
10、dva的了解
11、了解整个项目的流程,开始提需求到提测上线
12、git的使用与理解