组件复用策略
组件开发规范和复用策略是前端工程化的重要部分,直接影响项目的可维护性和开发效率。规范的组件设计能减少重复劳动,提升团队协作质量,而合理的复用策略则能最大化代码价值。
组件设计原则
单一职责原则
每个组件应只解决一个特定问题。例如按钮组件只处理点击交互,不包含业务逻辑:
// 不推荐:混合业务逻辑
function OrderButton() {
const handleClick = () => {
fetch('/api/order').then(/*...*/)
}
return <button onClick={handleClick}>下单</button>
}
// 推荐:纯UI组件
function Button({ onClick, children }) {
return <button onClick={onClick}>{children}</button>
}
受控与非受控设计
明确区分组件状态管理方式:
- 受控组件:状态由父组件完全控制
- 非受控组件:维护自身内部状态
// 受控输入框
function ControlledInput({ value, onChange }) {
return <input value={value} onChange={onChange} />
}
// 非受控输入框
function UncontrolledInput({ defaultValue }) {
const [value, setValue] = useState(defaultValue)
return <input value={value} onChange={e => setValue(e.target.value)} />
}
接口规范
Props设计准则
- 使用TS/PropTypes明确定义类型
- 布尔类型prop命名需带
is
/has
前缀 - 事件回调prop使用
on
前缀
interface ModalProps {
isOpen: boolean
title: string
onClose: () => void
children?: React.ReactNode
}
默认值与必填项
通过默认参数处理可选prop:
function Avatar({ size = 'medium', src }) {
const sizes = {
small: 32,
medium: 48,
large: 64
}
return <img width={sizes[size]} src={src} />
}
样式处理方案
CSS作用域隔离
推荐方案优先级:
- CSS Modules
- Styled Components
- Scoped CSS
/* Button.module.css */
.primary {
background: #1890ff;
color: white;
}
import styles from './Button.module.css'
function Button({ type }) {
return <button className={styles[type]} />
}
组件复用模式
高阶组件(HOC)
适用于横切关注点复用:
function withLoading(Component) {
return function WrappedComponent({ isLoading, ...props }) {
return isLoading ? <Spinner /> : <Component {...props} />
}
}
const EnhancedTable = withLoading(DataTable)
渲染属性(Render Props)
提供更灵活的复用方式:
<MouseTracker>
{({ x, y }) => (
<div>当前鼠标位置: {x}, {y}</div>
)}
</MouseTracker>
文档与示例
Storybook集成
为每个组件创建可视化文档:
// Button.stories.js
export default {
title: 'Components/Button',
component: Button
}
export const Primary = () => <Button type="primary">提交</Button>
版本管理与更新
语义化版本控制
组件库版本遵循MAJOR.MINOR.PATCH
原则:
- MAJOR:破坏性变更
- MINOR:向后兼容的功能新增
- PATCH:问题修复
变更日志规范
每个版本更新需包含:
- 新增功能 2 问题修复
- 破坏性变更说明
## [1.2.0] - 2023-05-20
### Added
- Button组件新增loading状态属性
### Fixed
- 修复Modal组件内存泄漏问题
性能优化策略
记忆化处理
对复杂计算进行缓存:
const MemoizedComponent = React.memo(function MyComponent({ list }) {
const sortedList = useMemo(() => {
return list.sort(/* 复杂计算 */)
}, [list])
return <div>{sortedList.map(/*...*/)}</div>
})
虚拟滚动实现
处理大数据量渲染:
function VirtualList({ items, itemHeight, renderItem }) {
const [startIndex, setStartIndex] = useState(0)
const visibleCount = Math.ceil(window.innerHeight / itemHeight)
return (
<div style={{ height: items.length * itemHeight }}>
{items.slice(startIndex, startIndex + visibleCount).map((item, i) => (
<div key={i} style={{ position: 'absolute', top: (startIndex + i) * itemHeight }}>
{renderItem(item)}
</div>
))}
</div>
)
}
测试策略
单元测试覆盖
使用Jest+Testing Library组合:
test('Button点击触发回调', () => {
const handleClick = jest.fn()
render(<Button onClick={handleClick} />)
fireEvent.click(screen.getByRole('button'))
expect(handleClick).toHaveBeenCalled()
})
视觉回归测试
通过Storybook+Chromatic实现:
npx chromatic --project-token=<your_token>
多端适配方案
响应式设计
使用CSS媒体查询:
@media (max-width: 768px) {
.container {
flex-direction: column;
}
}
条件渲染
根据设备特性渲染不同内容:
function ResponsiveComponent() {
const isMobile = useMediaQuery('(max-width: 768px)')
return isMobile ? <MobileView /> : <DesktopView />
}
国际化支持
多语言组件设计
通过上下文提供语言包:
const I18nContext = createContext()
function App() {
const [locale, setLocale] = useState('zh-CN')
return (
<I18nContext.Provider value={locale}>
<Navbar onChangeLanguage={setLocale} />
<Content />
</I18nContext.Provider>
)
}
function useTranslation() {
const locale = useContext(I18nContext)
return key => translations[locale][key]
}
主题化方案
CSS变量控制
实现动态主题切换:
:root {
--primary-color: #1890ff;
--text-color: #333;
}
.dark {
--primary-color: #177ddc;
--text-color: #eee;
}
function ThemeToggle() {
const [isDark, setIsDark] = useState(false)
useEffect(() => {
document.body.className = isDark ? 'dark' : ''
}, [isDark])
return <Switch checked={isDark} onChange={setIsDark} />
}
组件分类体系
原子设计方法论
建立清晰的组件层级:
- Atoms(原子):按钮、输入框等基础元素
- Molecules(分子):搜索框=输入框+按钮
- Organisms(有机体):导航栏=Logo+菜单+用户面板
- Templates(模板):页面骨架布局
- Pages(页面):具体业务页面
代码分割策略
动态导入组件
按需加载提升性能:
const HeavyComponent = React.lazy(() => import('./HeavyComponent'))
function App() {
return (
<Suspense fallback={<Spinner />}>
<HeavyComponent />
</Suspense>
)
}
错误边界处理
组件级错误捕获
防止局部UI崩溃影响整体:
class ErrorBoundary extends React.Component {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true }
}
render() {
if (this.state.hasError) {
return <FallbackUI />
}
return this.props.children
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn