- 【必须】文件夹名用 - 形式命名文件夹名,如:reservation-card; React 组件用大驼峰;变量名用小驼峰
2.【必须】 变量的命名避免缩写
// bad 自我感觉良好的缩写:
let fName = 'jackie'; // 看起来命名挺规范,缩写,驼峰法都用上,ESlint各种检测规范的工具都通过,But,fName是啥?这时候,你是不是想说What are you 弄啥呢?
let rContent = 'willen';
// good 无需对每个变量都写注释,从名字上就看懂
let firstName = 'jackie';
let rightContent = 'willen';
- 【必须】 兼容可能不存在的属性
// bad
const data = await getPeopleList(keyword, page, pageSize);
data.dataList.forEach() // 直接挂了
// good
const data = await getPeopleList(keyword, page, pageSize);
data?.dataList?.forEach()
- 【推荐】单个文件代码行数不要超过200行
- **【必须】**避免使用魔法数字
// bad
if (type !== 0) {
// TODO
}
// good
enum STATUS {
// 就绪
READY = 0,
// 请求中
FETCHING = 1,
// 请求失败
FAILED = 2,
}
- 【必须】路由懒加载
// bad
import OtherComponent from './OtherComponent';
// good
const OtherComponent = React.lazy(() => import('./OtherComponent'));
- 【必须】防止 xss 攻击
input,textarea 等标签,不要直接把 html 文本直接渲染在页面上,使用 DOMPurify 等过滤之后再输出到标签上
import DOMPurify from 'dompurify';
render(){
<div
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(htmlContent)
}}
/>
}
- 【必须】整个应用程序中保持你的key 的唯一性
使用key 是很重要的,因为它可以帮助React识别已经改变的、被添加或被移除的确切元素。React需要弄清楚以前的UI和新的UI之间的差异,以便更新它。
- **【必须】**使用Fragement 来避免无用的嵌套标签
// bad
const InfoText = () => {
return (
<div>
<h1>Welcome!</h1>
<p>This our new page, we're glad you're are here!</p>
</div>
)
}
// good
const InfoText = () => {
return (
<>
<h1>Welcome!</h1>
<p>This our new page, we're glad you're are here!</p>
</>
)
}
- **【必须】**每个文件只包含一个 React 组件。
// src/pages/user.jsx
// bad
const Age = () => {
const [age, setAge] = useState(18);
return <div>{age}</div>;
};
const Name = () => {
const [name, setName] = useState("echo");
return <div>{name}</div>;
};
- 【必须】避免嵌套渲染函数
组件应该只有属于它本身的功能,嵌套组件可以访问其父级的所有状态和数据。它使代码更难读将它移动到它自己的组件中,命名它并传递props,而不是以闭包的形式存在。
// bad 不要将其定义在渲染函数组件中
function Component() {
function renderHeader() {
return <header>...</header>
}
return <div>{renderHeader()}</div>
}
// good 将其抽离到独立的组件中去
import Header from '@modules/common/components/Header'
function Component() {
return (
<div>
<Header />
</div>
)
}
- 【必须】避免嵌套三元运算符
// bad 不够清晰,要是再嵌套一层两层呢
isSubscribed ? (
<ArticleRecommendations />
) : isRegistered ? (
<SubscribeCallToAction />
) : (
<RegisterCallToAction />
)
// good 将判断逻辑进行拆分
function CallToActionWidget({ subscribed, registered }) {
if (subscribed) {
return <ArticleRecommendations />
}
if (registered) {
return <SubscribeCallToAction />
}
return <RegisterCallToAction />
}
function Component() {
return (
<CallToActionWidget
subscribed={subscribed}
registered={registered}
/>
)
}
- 【推荐】 在jsx Props中禁用箭头函数函数 eslint:
[react/jsx-no-bind](<https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md>)
// bad
<Foo onClick={() => console.log('Hello!')}></Foo>
- **【推荐】 **以正确的顺序创建函数组件
建议先使用 useState Hook 声明状态变量,然后使用 useEffect Hook 编写订阅,接着编写与组件业务相关的其他函数。最后,你得返回要由浏览器渲染的元素:
function App() {
const [user, setUser] = useState(null);
const [name, setName] = useState('');
useEffect(() => {
console.log("component is mounted");
}, []);
return <h1>React component order</h1>;
}
- 【推荐】 状态提升
如果多个组件需要反映相同的变化数据,建议将共享状态提升到最近的共同父组件中去;从而依靠自上而下的数据流,而不是尝试在不同组件间同步 state。
- 【推荐】 props传参数量不超过5个
如果超过 5 个props,就该考虑是否拆分该组件,props越多 重新渲染的原因也就越多
- 【推荐】 解构Props
// bad 不要在组件中到处重复传递props
function Input(props) {
return <input value={props.value} onChange={props.onChange} {...props}/>
}
// good 对props解构并使用这些值
function Component({ value, onChange }) {
const [state, setState] = useState('')
return <div>...</div>
}
18.**【推荐】**传递对象而不是基础数据
// bad 如果值都是相关的,不用一个一个传递
<UserProfile
bio={user.bio}
name={user.name}
email={user.email}
subscription={user.subscription}
/>
// good 使用对象进行传递,在后期增改字段也更方便
<UserProfile user={user} />
- 【推荐】使用布尔型props的速记
// bad
<RegistrationForm hasPadding={true} withError={true} />
// good
<RegistrationForm hasPadding withError />
- 【必须】当你想使用一个字符串时,避免使用大括号;当使用JavaScript表达式时,才使用大括号
当你想使用一个不同于字符串的JavaScript表达式时,你需要使用大括号
// bad
<Paragraph variant={"h5"} heading={"A new book"} />
// good
<Paragraph variant="h5" heading="A new book" />
- **【推荐】**惰性初始state
需要复杂计算的初始state 避免在render过程中被频繁计算
//bad
const initalState = heavyCompute(() => { /* do some heavy compute here*/});
const [state,useState] = useState(initalState);
// good
// 这样初始值就只会被计算一次了
const [state,useState] = useState(() => heavyCompute(() => { /* do some heavy compute here*/}););
- 【推荐】 避免state颗粒度过细,
// bad
const {name,age,height} = data
setName(name)
setAge(age)
setHeight(height)
//good
const {name,age,height} = data
setUser({name,age,height})
- 【必须】 避免无意义的state
对于可以直接复用props 的场景不需要在子组件内维护state
// bad
function FatherComponent() {
const [name, setName] = useState('andy')
return <SonComponent name={name}/>
}
// good 对props解构并使用这些值
function SonComponent({ name}) {
const [sonName, setSonName] = useState(()=>name)
return <div>{sonName}</div>
}
- 【必须】在 componentWillUnmount 里面去除副作用的函数
- 清除 EventListener
- 中止数据请求
- 清除定时器
- **【推荐】**正确的使用useCallback
在大多数情况下,javascript 创建一个函数的开销是很小的,哪怕每次渲染都重新创建。真正的性能损耗在于,很多时候 callback 函数是组件 props 的一部分,维持函数引用,在只需要维持函数引用的情况下推荐使用 useCallback,当需要借助依赖维持引用推荐使用 useMemoizedFn。
A const [count, setCount] = useState(0);
const callbackFn = useCallback(() => {
console.log('123')
}, []);
const callbackFnDep = useCallback(() => {
console.log('count',count)
}, [count]);
const callbackFnDep = useCallback(() => {
console.log('count',count)
}, [count]);
const memoizedFn = useMemoizedFn(() => {
message.info(`Current count is ${count}`);
});
return (
<>
<ExpensiveTree showCount={callbackFn} />
// bad
<ExpensiveTree showCount={callbackFnDep} />
// good
<ExpensiveTree showCount={memoizedFn} />
</>
);
};
- 【推荐】避免滥用 useMemo
滥用 useMemo 会带来性能损耗,推荐在需要缓存复杂计算值的场景下使用useMemo
//bad
const Comp = () => {
const data = useMemo(() => ({ type: 'xxx' }), []);
return <Child data={data}>;
}
// good
const Comp = () => {
const { current: data } = useRef({ type: 'xxx' });
return <Child data={data}>;
}
// good
const data = { type: 'xxx' };
const Comp = () => {
return <Child data={data}>;
}
// good
const Comp = () => {
const data = useMemo(() => { //复杂计算 }, []);
return <Child data={data}>;
}
- 【必须】将可重复使用的逻辑提取到自定义hook
const useWindowSize = () => {
const [windowSize, setWindowSize] = useState({ju
width: undefined,
height: undefined,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
handleResize();
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}
const ScreenDimensions = () => {
const windowSize = useWindowSize()
return (
<>
<p>Current screen width: {windowSize.width}</p>
<p>Current screen height: {windowSize.height}</p>
</>
)
}
- 【必须】多语言字符串,不要随意将两个key对应的字符串拼接使用
不同语言的语言习惯和语序不同,基于中文拼接出的词组,在其他语言中可能就错了
// bad
placeholder
? `${t('common.search')}${placeholder}`
: placeholder || t('common.pleaseEnterContent')
- 【推荐】避免组件嵌套过深
组件一般不要超过三层,最多四层,层级过深可能会导致数据传递过深,在做一些颗粒度比较细的操作的时候,处理起来较为繁琐,可以使用 redux 等状态管理工具替代。