Event Handling Specification
Component development specifications and event handling specifications are important parts of front-end engineering. Reasonable specifications can improve code maintainability and team collaboration efficiency. Below is a detailed explanation from two aspects: component development and event handling.
Component Development Specifications
Component Naming Convention
Component names should use PascalCase and match the file name. Avoid abbreviations for multi-word combinations to maintain semantic integrity.
// Good
UserProfileCard.jsx
OrderStatusBadge.jsx
// Bad
userProfile.jsx // Not PascalCase
usrPrfCard.jsx // Abbreviations not recommended
Directory Structure
Component-related files should be placed in the components
directory, with complex components having their own folders:
src/
components/
Button/
index.jsx
style.module.css
Button.test.js
Form/
Input/
index.jsx
InputItem.jsx
Props Type Definition
Props types must be explicitly defined using TypeScript or PropTypes:
interface ButtonProps {
size?: 'small' | 'medium' | 'large';
variant?: 'primary' | 'secondary';
disabled?: boolean;
onClick?: (event: React.MouseEvent) => void;
}
const Button: React.FC<ButtonProps> = ({
size = 'medium',
variant = 'primary',
...props
}) => {
/* ... */
}
Style Management
CSS Modules or styled-components are recommended:
// CSS Modules example
import styles from './Button.module.css';
const Button = () => (
<button className={`${styles.btn} ${styles.primary}`}>
Click
</button>
);
// styled-components example
const StyledButton = styled.button`
padding: ${props => props.size === 'large' ? '12px 24px' : '8px 16px'};
background: ${props => props.theme.primary};
`;
Event Handling Specifications
Naming Convention
Event handler functions should start with the handle
prefix, and callback props should start with the on
prefix:
const handleClick = (e) => {
console.log('Button clicked', e.target);
};
<Button onClick={handleClick} />
// Exposing events inside components
function Modal({ onClose }) {
const handleClose = () => {
// Cleanup logic...
onClose?.();
};
}
Event Object Handling
Always consider event delegation and preventing default behavior:
// List item click event delegation
function List({ items }) {
const handleClick = (e) => {
const itemId = e.target.dataset.id;
if (itemId) {
// Handle specific item click
}
};
return (
<ul onClick={handleClick}>
{items.map(item => (
<li key={item.id} data-id={item.id}>{item.text}</li>
))}
</ul>
);
}
// Form submission
const handleSubmit = (e) => {
e.preventDefault();
// Validate and process data
};
Asynchronous Event Handling
Loading states and error catching must be handled:
function AsyncButton() {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
try {
setLoading(true);
await fetchData();
} catch (error) {
console.error('Fetch failed:', error);
} finally {
setLoading(false);
}
};
return <button onClick={handleClick} disabled={loading} />;
}
Custom Events
Complex components should define detailed event contracts:
// Type definition
type CalendarEvent = {
date: Date;
type: 'select' | 'hover';
nativeEvent: React.MouseEvent;
};
interface CalendarProps {
onDateChange?: (event: CalendarEvent) => void;
}
// Event triggering
const emitDateChange = (date: Date, type: CalendarEvent['type'], e: React.MouseEvent) => {
onDateChange?.({
date,
type,
nativeEvent: e
});
};
Performance Optimization
Event Throttling and Debouncing
High-frequency events require performance optimization:
import { throttle, debounce } from 'lodash-es';
// Throttle scroll events
const handleScroll = throttle((e) => {
console.log('Scrolling', e.target.scrollTop);
}, 200);
// Debounce search input
const handleSearch = debounce((keyword) => {
searchAPI(keyword);
}, 500);
Event Listener Cleanup
Global event listeners must be removed when the component unmounts:
useEffect(() => {
const handleKeyDown = (e) => {
if (e.key === 'Escape') handleClose();
};
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, []);
Accessibility Standards
Keyboard Events
Keyboard operations must be supported:
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick();
}
}}
>
Clickable element
</div>
ARIA Attributes
Complex components should include ARIA attributes:
<div
role="dialog"
aria-labelledby="dialog-title"
aria-modal="true"
>
<h2 id="dialog-title">Prompt</h2>
{/* Dialog content */}
</div>
Testing Standards
Event Test Cases
Use Testing Library to write event tests:
import { render, fireEvent } from '@testing-library/react';
test('should trigger onClick', () => {
const handleClick = jest.fn();
const { getByText } = render(<Button onClick={handleClick} />);
fireEvent.click(getByText('Submit'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
// Simulate keyboard events
test('should handle keyboard event', () => {
const { getByRole } = render(<SearchBox />);
const input = getByRole('searchbox');
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
// Verify search logic
});
Documentation Standards
Component Documentation
Use Storybook or JSDoc to document component events:
/**
* Generic button component
*
* @param {Object} props - Component props
* @param {'small'|'medium'|'large'} [props.size=medium] - Button size
* @param {Function} props.onClick - Click event callback
*/
export function Button({ size = 'medium', onClick }) {
// ...
}
Event Flow Diagram
For complex interactions, it is recommended to draw an event flow diagram:
User click → Triggers handleClick → Validates data → Calls onSubmit → Initiates API request
↑ ↓
Error feedback ← Request fails
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn