【组件开发笔记】组件の组织
1、组件设计基本原则
单一职责。
也就是:
① 降低组件的复杂度,减少代码量,提升可读性。
② 降低与其他组件的耦合度(低耦合),从而降低变更导致的对功能的影响。
③ 提高可复用性,功能单一(高内聚),有明确的边界,不访问其他组件的内部细节,接口最小化,单向数据流...。
2、TIPs
性能:无状态函数组件 > 有状态函数组件 > class组件;
减少props传递;
抽取过多的条件控制流;
不过度优化;
3、分类
【展示组件】-【本质:视图】
通用的组件:开发时,要以“第三方组件库”的标准考虑其设计,不和任何项目的业务耦合。
项目通用的组件:可多个组件共享,可能与业务有较低耦合程度。
组件特有的组件库:与业务深度耦合,不能与其他组件共享。
【容器组件】-【本质:逻辑】
侧重业务处理,通常为高阶组件。
数据来源:直接请求接口或从外部传入。
然后展示完整的视图。
【有状态组件&无状态组件】
无状态组件完全由外部props控制状态。如果想要优化它的props映射,提升性能,可以使用React.memo避免无用渲染。
React.memo类似于React.PureComponent,两者的区别为:React.memo是用于函数组件的,React.PureComponent是用于类组件的。
React.memo的用法为:
const Component = ()=> {
return (
<div>嘎嘎嘎</div>
)
}
const MemodFuncComponent = React.memo(Component)
React.PureComponent 的用法为:
import React from 'react';
class Test extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate')
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate')
}
render() {
return (
<div>
{ this.state.count }
<button onClick = {
() => this.setState({ count: 1 })
}>点击</button>
</div >
);
}
}
export default Test;
React在进行组件更新时,如果发现这个组件是一个PureComponent,它会将组件现在的state和props和其下一个state和props进行浅比较,如果它们的值没有变化,就不会进行更新。
类似于写了一个shouldComponentUpdate生命周期,判断nextProps和nextState是否有变化:
import React from 'react';
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate')
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate')
}
shouldComponentUpdate(nextProps, nextState) {
// 如果没变化,就不渲染,否则重新渲染
if (this.state.count === nextState.count) {
return false
}
return true
}
render() {
return (
<div>
{ this.state.count }
<button onClick = {
() => this.setState({ count: 1 }) }>点我</button>
</div>
);
}
}
export default Test;
【纯组件&非纯组件】
纯组件其实类似于纯函数的概念。
纯组件就是[单向],给定输入,就永远返回相同的输出,过程没有副作用与外部的状态依赖(props,state,context没有变化,则输出没有变化),也就代表着这个组件不需要重新渲染,从而提高性能收益。
而很多个组件组成的比较复杂的组件树,则需要外部去维护它的状态,然后通过注入依赖,展示相对应的视图,这样可以维持组件树的纯净性。比较典型的解决方案是Redux,它把组件树看做一个状态树,分离逻辑与视图,再配合异步处理,就可以实现单向的数据流。类似的还有Cycle.js,有空学习。(#^.^#) (但还是附个链接: http://cyclejs.cn/#-%E7%BB%84%E4%BB%B6%E5%8C%96)
【布局组件&内容组件】
内容组件通常被约束在布局组件的占位中。抽离开来可以避免互相影响,提高可维护性。
布局组件:Grid, Layout, HorizontalSplit……
内容组件:Button, Label, Input……
【表单组件】
沿用通用的属性,保证兼容,减少代码重复,使用方便。
组件受控。实际开发中非受控组件的场景非常少, 自定义组件应只提供完全受控表单组件,避免组件自身维护缓存状态。
4、目录

大牛推荐的多页面目录:
src/
components/ # 共享组件
containers/
Admin/ # 后台管理页面
components/ # 后台特定的组件库
LoginPage/
index.tsx
...
App/
components/ # App特定的组件库
LoginPage/ # App页面
index.tsx
stores.ts # redux stores
AnotherApp/ # 另外一个App页面
hooks/
...
app.tsx # 应用入口
anotherApp.tsx # 应用入口
admin.tsx # 后台入口

。。。。。。
还有一些没用过的目录划分方式,有空学习。(#^.^#)
5、模块
每个目录都是一个模块,都应该有一个index的唯一出口文件来统一管理模块的导出(限定模块的可见性)
(除了utils文件夹,它只是一块模块命名空间,因为它目录下是互不相关或不同类型的文件)
相对路径不超过两级(即../和./)
或者将相对路径转为绝对路径, 例如webpack中可以配置resolve.alias属性来实现(直接copy一下大佬的代码):
...
resolve: {
...
alias: {
// 可以直接使用~访问相对于src目录的模块
// 如 ~/components/Button
'~': context,
},
}
然后就可以:import { hide } from '~/utils/dom';
6、组件拆分
①拆分为render方法,比如:
// 生成数据列表工具栏
const renderToolBar = () => {
const toolBarList: ReactNode[] = [
<Btn key="showMetrics" type="primary" onClick={showMetrics}>
自定义指标
</Btn>,
rowKey ==='key' && <DownloadEfforts columnsData={columnsData} totalList={totalList} tableInfo={tableInfo} searchParams={searchParams} key="downloadExcel" dataType="effect"/>,
rowKey ==='materialId' && <DownloadEfforts columnsData={columnsData} totalList={totalList} tableInfo={tableInfo} searchParams={searchParams} key="downloadExcel" dataType="materialRank"/>,
(rowKey === 'adId' || rowKey === 'creativeId') && <DownloadEfforts columnsData={columnsData} tableInfo={tableInfo} searchParams={searchParams} key="downloadExcel" dataType="relation"/>,
];
return toolBarList;
};
return (
<BasisTable
...
operateToolBar={() => renderToolBar()}
/>
)
但是这个方法只是在return处简化了代码,其实并没有真的实现组件的拆分。
当代码行数超过300这个阈值,就要进行组件进一步拆分。
②拆分为组件
- 纯UI渲染拆分为组件
- 纯逻辑内容拆分到hooks中 || 拆分到高阶组件中
- 两者皆有:将相关视图&逻辑都抽离,形成一个独立组件
7、组件文档化
https://storybook.js.org/
推荐用storybook.js进行文档化,用过,还是挺好上手的,就不赘述了。

浙公网安备 33010602011771号