React 开发规范
以下都本人开发过程中所践行的规范,总结一波。如果对各位有所帮助就perfect了。
命名
- 文件夹:使用中划线,如: any-modal
- 组件、类、接口、类型:使用帕斯卡+驼峰命名
const AnyModal:React.FC<AnyFnProps>
class AnyClass
interface AnyInterface
type AntType
- 高阶组件:驼峰命名。
- 返回组件的命名为:高阶组件名+ { 传入组件displayName | 传入组件name | 'Component' }(displayName > name > 'component')
- 属性:驼峰命名。若值为true省略赋值。
组件规范
- 函数组件使用模板
type AnyFcProps = {
val:string;
isProps?:boolean;
onChange:() => void;
};
const AnyFc:React.FC<AnyFcProps>=(props)=>{
const {val, onChange} = props;
// 状态
// 副作用
// 函数
return (
<div onClick={()=>onChange()}>
{val}
</div>
)
}
AnyFc.defaultProps = {
isProps:false // 非必要属性默认值
}
export AnyFcComponent = React.memo(AnyFc)
- 对齐方式
// 方式1 <AnyFcComponent props1="foo1" /> // 方式2 <AnyFcComponent props1="foo1" props2 /> // 方式3 <AnyFcComponent props1="foo1" props2 />
通讯
- 3层内,使用props
- 层级超3层,使用redux
- redux实现数据的传递不能实现某些场景时可以试着用pubsub-js(实现了兄弟组件间的数据传递)
redux使用规范
- store结构
- 结构不要太深
- 减少冗余,设计成类似于关系数据库的结构
- 使用索引保存数据,使用选择器读取数据
- redux-saga
- 使用spawn,防止一个saga的异常导致所有saga无法正常工作
- 创建saga时需要监听error,防止某个sub_saga为捕获的错误,导致整个系统的崩溃
// 创建 saga 中间件
const sagaMiddleware = createSagaMiddleware({
onError: (error: Error) => {
// saga中未被捕获的错误
console.log('error===', error);
},
});
- 使用try/catch捕获异常
function* sagaFn() {
try {
const res = yield call(getDataApi);
return res;
} catch(e) {
logger.error('request error: ', e);// 错误日志上报
message.error('xxxx'); // 错误提示
}
}
- API使用
- fork:非阻塞,返回task用于取消fork
- call:阻塞generator
- take+while(true):连续触发action,上次action结束才会触发下一次
- takeEvery:只要注册,每次action都会响应,允许多个请求同时执行,不管之前是否有请求尚未结束是非阻塞的
- takeLatest:只响应最近一次的异步action请求,如果之前还未结束就会被取消。
// take+while(true)
while(true) {
yield take(pattern);
yield call(fetchData);
}
// takeEvery
takeEvery(pattern, () => {
yield call(fetchData);
});
//takeEvery原理
const takeEvery = (pattern, saga, ...args) => {
while (true) {
const action = yield take(pattern)
yield fork(saga, ...args.concat(action))
}
}
// ./sagas
function* checkout() {
const cart = yield select(getCart)
}
while (true) {
yield take('CHECKOUT_REQUEST')
yield fork(checkout)
}
// saga checkout 仅与getCart选择相耦合,这样可以在多个saga共享getCart选择器,并且如果state结构变化,只需要更新getCart
- 文件结构
├── module
│ ├── index.ts
│ └── saga.ts
│ └── thunk.ts(若使用Thunk,使用次文件)
├── root_reducer.ts // 使用combineReducers集合所有的reducer
├── root-saga.ts // 集合所有saga
└── root-store.ts // 创建store,管理所有的middleware
typescript规范
- 变量名
- 变量:驼峰;常量:大写+下划线
- 类、接口类型使用驼峰并首字母大写
- 私有变量使用 _ 为开头
- 空格
- 一元运算不用空格
- 二运运算空格
- 一般2格缩进,多行使用4格缩进
- 导入与导出
- 不要使用
export default XXX
来进行导出 - 避免单行代码过长
sass规范
- 使用
@use
,不建议使用@import
,@use
解决了@import
的一下问题
- 使所有的变量、混合指令(mixin)、方法等变成全局,难以定位定义位置。
- 由于所有的都是全局的,所以库内部的命名要加前缀防止命名冲突。
- @extend规则也会变为全局的,所以很难预测哪个style的规则会被继承。
- 每次@import都会被执行,增加编译时间,容易产生冗余css。
- 无法定义私有变量。
未完待续