组件
1、基本规则
- 一个文件声明一个组件
- 使用 JSX 语法
- 使用 Class、函数或 Hooks 声明组件,不使用 React.createElement
2、组件名
(1) 组件名称和定义该组件的文件名称尽量保持一致,名称尽量简短
// Good
import MyComponent from './MyComponent';
// Bad
import MyComponent from './MyComponent/index';
(2) 应在 class、function(箭头函数就是 const 关键字) 关键字或 声明后面直接声明组件名称,不要使用 displayName 来命名 React 模块
// Good
export default class MyComponent extends React.Component {}
const MyField = (props) => {
return <></>;
};
// bad
export default React.createClass({
displayName: 'MyComponent',
});
(3) 组件名称应全局唯一
很多业务都会有相同的文件命名,此时应在声明组件名称时保持全局唯一。一般是将业务链路名称全拼至组件声明
// Account/User/List.jsx
// Good
export default class AccountUserList extends React.Component {}
// Bad
export default class List extends React.Component {}
(4)高阶组件名
// bad
export default function withFoo(WrappedComponent) {
return function WithFoo(props) {
return <WrappedComponent {...props} foo />;
};
}
// good
export default function withFoo(WrappedComponent) {
function WithFoo(props) {
return <WrappedComponent {...props} foo />;
}
const wrappedComponentName =
WrappedComponent.displayName || WrappedComponent.name || 'Component';
WithFoo.displayName = `withFoo(${wrappedComponentName})`;
return WithFoo;
}
3、组件文件名
(1)组件文件后缀为 jsx、tsx包含 jsx 语法的应启用 jsx 后缀作为组件后缀
(2)组件文件名为 PascalCase 大驼峰格式
components/
|- MyComponents.jsx
(3) 组件文件夹名称和默认导出一个组件可以被拆分成多个组件编写的应建立目录,目录使用 PascalCase。建立 index.jsx 导出对象。
components/
|- MyComponent/
|----index.jsx
|----MyComponentList.jsx
|----MyComponentListItem.jsx
4、创建组件
组件有内部状态或是 refs 引用 使用 React.Component`
export default class ShowName extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'foo',
};
}
render() {
const { name } = this.state;
return <div>{name}</div>;
}
}
组件没有状态或 refs 可以使用函数组件
const ShowName = ({ name }) => <div>{name}</div>;
5、Hooks
组件中有状态或事件响应且运行更新逻辑清晰的才可以使用 Hooks,否则都应使用 Class
// Good
import React, { useState, useEffect } from 'react';
import { Modal, Form, Checkbox } from 'antd';
const AutoModal = (props) => {
const { visible, formItemLayout, customerFlag, csFlag } = props;
const [confirmLoading, setConfirmLoading] = useState(false);
const [form] = Form.useForm();
const [csFlagState, setCsFlagState] = useState(csFlag);
const [customerFlagState, setCustomerFlagState] = useState(customerFlag);
const handleFinish = async (values) => {
try {
setConfirmLoading(true);
await handleOk(values);
} catch (e) {
console.error(e);
} finally {
setConfirmLoading(false);
}
};
const handleOk = () => {
form.submit();
};
const handleCancel = () => {};
const handleCSFlagChange = (e) => {
setCsFlagState(e.target.checked);
};
const handleCustomerFlagChange = (e) => {
setCustomerFlagState(e.target.checked);
};
const checkFlag = () => {
if (csFlagState || customerFlagState) {
return Promise.resolve();
}
message.warning('服务客服或服务客户至少选一项');
return Promise.reject(new Error('服务客服或服务客户至少选一项'));
};
useEffect(() => {
// 使用visible防止出现useForm报错
if (visible) {
form.setFieldsValue({
newTskId: modifyObj.tskId,
creIdList: modifyObj.creIdList,
custIdList: modifyObj.custIdList,
});
}
}, [modifyObj, visible, form]);
useEffect(() => {
if (visible) {
form.setFieldsValue({
csFlag,
});
setCsFlagState(csFlag);
}
}, [csFlag, visible, form]);
useEffect(() => {
if (visible) {
form.setFieldsValue({
customeFlag: customerFlag,
});
setCustomerFlagState(customerFlag);
}
}, [customerFlag, visible, form]);
return (
<Modal
forceRender
title={title}
visible={visible}
onOk={handleOk}
confirmLoading={confirmLoading}
onCancel={handleCancel}
destroyOnClose
>
<Form
form={form}
preserve="false"
onFinish={handleFinish}
layout="horizontal"
{...formItemLayout}
>
<Form.Item
{...formItemLayout}
style={{ marginBottom: 0 }}
label={
<Form.Item
noStyle
name="csFlag"
rules={[{ validator: checkFlag }]}
validateTrigger="onSubmit"
initialValue={csFlagState}
valuePropName="checked"
>
<Checkbox onChange={handleCSFlagChange}>{csLabel}</Checkbox>
</Form.Item>
}
></Form.Item>
<Form.Item
{...formItemLayout}
style={{ marginBottom: 0 }}
label={
<Form.Item
noStyle
name="customeFlag"
rules={[{ validator: checkFlag }]}
validateTrigger="onSubmit"
initialValue={customerFlagState}
valuePropName="checked"
>
<Checkbox onChange={handleCustomerFlagChange}>
{customerLabel}
</Checkbox>
</Form.Item>
}
></Form.Item>
</Form>
</Modal>
);
};
export default AutoModal;
6、组件中的命名规则
- 属性名称: 使用小驼峰命名
- style 样式: 使用小驼峰命名的样式属性
7、组件样式
使用 CSS Modules 编写局部样式组件,因为其对象是作为对象在 jsx 中使用,样式应使用小驼峰命名`
.myWrapper {
&-Text {
}
}
import styles from 'style.less';
export default class MyComponent extends React.Component {
render() {
return (
<div className={styles.myWrapper}>
<p className={styles.myWrapperText}></p>
</div>
);
}
}