Component design principles
Component development standards and design principles form the foundation for building high-quality frontend applications. Good standards enhance code maintainability and readability, while sound design principles ensure component reusability and extensibility. From naming conventions to state management, from style isolation to API design, each step must strictly adhere to best practices.
Naming Conventions
Component names should use PascalCase and match the filename. For base components, a unified prefix should be added for better identification:
// Correct example
import Button from './BaseButton';
import IconClose from './IconClose';
// Incorrect example
import btn from './button';
CSS class names should follow the BEM methodology, using double underscores for elements and double hyphens for modifiers:
/* Correct example */
.menu__item--active {
color: #1890ff;
}
/* Incorrect example */
.menu .active-item {
color: red;
}
Single Responsibility Principle
Each component should address only one specific problem. When a component handles too many functions, it should be split:
// Overly complex component
function UserProfile({ user, onEdit, onDelete }) {
return (
<div>
<Avatar src={user.avatar} />
<h2>{user.name}</h2>
<p>{user.bio}</p>
<button onClick={onEdit}>Edit</button>
<button onClick={onDelete}>Delete</button>
</div>
);
}
// Split into single-purpose components
function UserAvatar({ src, alt }) {
return <Avatar src={src} alt={alt} />;
}
function UserActions({ onEdit, onDelete }) {
return (
<>
<button onClick={onEdit}>Edit</button>
<button onClick={onDelete}>Delete</button>
</>
);
}
Controlled vs. Uncontrolled Components
Form components must clearly distinguish between controlled and uncontrolled modes. Controlled components fully manage state via props:
// Controlled input
function ControlledInput({ value, onChange }) {
return <input value={value} onChange={onChange} />;
}
Uncontrolled components use refs to access DOM element values, suitable for scenarios where form data is only needed upon submission:
// Uncontrolled input
function UncontrolledInput({ defaultValue }) {
const inputRef = useRef(null);
const handleSubmit = () => {
console.log(inputRef.current.value);
};
return (
<>
<input ref={inputRef} defaultValue={defaultValue} />
<button onClick={handleSubmit}>Submit</button>
</>
);
}
Style Isolation Solutions
Avoid global style pollution by adopting CSS Modules or styled-components:
// CSS Modules example
import styles from './Button.module.css';
function Button() {
return <button className={styles.primary}>Click</button>;
}
// styled-components example
const StyledButton = styled.button`
background: ${props => props.primary ? '#1890ff' : '#fff'};
padding: 8px 16px;
`;
Component API Design
Component props should follow the principle of minimal exposure, with type constraints using PropTypes or TypeScript:
interface ModalProps {
visible: boolean;
title?: string;
onClose: () => void;
width?: number | string;
}
function Modal({ visible, title, onClose, width = '50%' }: ModalProps) {
return (
<div className="modal" style={{ width }}>
{title && <h2>{title}</h2>}
<button onClick={onClose}>×</button>
</div>
);
}
State Management Strategies
Choose appropriate state management based on component hierarchy. Use useState for local state and Context for cross-component state:
// Create Context
const ThemeContext = createContext('light');
function App() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
<button onClick={() => setTheme('light')}>Toggle Theme</button>
</ThemeContext.Provider>
);
}
// Consume Context
function Toolbar() {
const theme = useContext(ThemeContext);
return <div className={theme}>Current Theme: {theme}</div>;
}
Performance Optimization Techniques
Use React.memo to avoid unnecessary renders and implement virtual scrolling for large lists:
// Optimize with memo
const MemoComponent = memo(function MyComponent({ data }) {
return <div>{data}</div>;
});
// Virtual list example
import { FixedSizeList as List } from 'react-window';
function VirtualList({ items }) {
return (
<List
height={400}
itemCount={items.length}
itemSize={50}
width={300}
>
{({ index, style }) => (
<div style={style}>Row {items[index]}</div>
)}
</List>
);
}
Error Boundary Handling
Use error boundary components to catch JavaScript errors in child component trees:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
logErrorToService(error, info);
}
render() {
if (this.state.hasError) {
return <FallbackUI />;
}
return this.props.children;
}
}
// Usage
<ErrorBoundary>
<UnstableComponent />
</ErrorBoundary>
Accessibility Requirements
Ensure components comply with WAI-ARIA standards, providing necessary information for screen readers:
function AccessibleButton({ children }) {
return (
<button
aria-label="Close dialog"
aria-pressed={false}
onClick={handleClick}
>
{children}
</button>
);
}
Documentation Standards
Each component should include a README with:
- Basic usage examples
- Detailed props description
- Event handling instructions
- Style override guidelines
- Notes and edge cases
## Button Component
### Basic Usage
```jsx
<Button type="primary">Confirm</Button>
Props
Prop | Type | Default | Description |
---|---|---|---|
type | 'primary'|'default' | 'default' | Button type |
disabled | boolean | false | Disabled state |
## Testing Strategy
Components should include unit tests and interaction tests to validate core functionality:
```jsx
// Jest test example
test('Button renders with correct text', () => {
const { getByText } = render(<Button>Submit</Button>);
expect(getByText('Submit')).toBeInTheDocument();
});
// Interaction test example
test('Button triggers onClick', () => {
const handleClick = jest.fn();
const { getByRole } = render(<Button onClick={handleClick} />);
fireEvent.click(getByRole('button'));
expect(handleClick).toHaveBeenCalled();
});
Version Compatibility
Component libraries must specify supported browser ranges and polyfill strategies:
// browserslist config in package.json
{
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version"
]
}
}
Internationalization Support
Component text content should support multilingual switching, avoiding hardcoding:
// Using i18n solution
function Greeting() {
const { t } = useTranslation();
return <h1>{t('welcome_message')}</h1>;
}
// Date localization
new Date().toLocaleDateString(navigator.language);
Theme Customization Solutions
Implement dynamic theming via CSS variables or theme Providers:
// CSS variables solution
:root {
--primary-color: #1890ff;
}
.button {
background: var(--primary-color);
}
// JS theme solution
const theme = {
colors: {
primary: '#1890ff'
}
};
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
Component Composition Patterns
Enable flexible composition via children props or render props:
// Children composition
function Card({ children }) {
return <div className="card">{children}</div>;
}
<Card>
<CardHeader />
<CardBody />
</Card>
// Render props pattern
function Toggle({ render }) {
const [on, setOn] = useState(false);
return render({ on, toggle: () => setOn(!on) });
}
<Toggle render={({ on, toggle }) => (
<button onClick={toggle}>{on ? 'ON' : 'OFF'}</button>
)} />
Type Definition Files
Provide TypeScript type declarations for JavaScript components:
// types/component.d.ts
declare module 'ui-library' {
interface ButtonProps {
size?: 'small' | 'medium' | 'large';
variant?: 'primary' | 'secondary';
}
export const Button: React.FC<ButtonProps>;
}
Build Output Standards
Component libraries should output multiple module formats:
// rollup.config.js
export default {
input: 'src/index.js',
output: [
{ file: 'dist/index.esm.js', format: 'es' },
{ file: 'dist/index.cjs.js', format: 'cjs' },
{ file: 'dist/index.umd.js', format: 'umd', name: 'ComponentLib' }
]
};
Release Process Control
Adopt semver versioning standards and follow commit message conventions:
# Standard version release command
npm version patch -m "fix: Resolve button click area issue"
npm publish
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn