- ESLint flat config + Prettier + EditorConfig - Markdown处理器LRU缓存 - Zustand选择器优化减少重渲染 - CodeMirror Compartment主题热切换 - Preview防抖(150ms) + IndexedDB去抖(500ms) - 组件拆分: App.tsx 310→104行, Sidebar.tsx 244→90行 - 统一错误处理 errorHandler.ts - ConfirmDialog替代原生confirm - LoadingSpinner加载状态 - Toast多条堆叠+类型区分 - 可访问性增强(ARIA属性、键盘导航) - Vitest测试框架(78个测试用例) - Git hooks(husky + lint-staged) - 项目文档(README.md, CONTRIBUTING.md)
88 lines
2.1 KiB
TypeScript
88 lines
2.1 KiB
TypeScript
import { Component, ErrorInfo, ReactNode } from 'react'
|
|
|
|
interface Props {
|
|
children: ReactNode
|
|
fallback?: ReactNode
|
|
}
|
|
|
|
interface State {
|
|
hasError: boolean
|
|
error: Error | null
|
|
}
|
|
|
|
export class ErrorBoundary extends Component<Props, State> {
|
|
constructor(props: Props) {
|
|
super(props)
|
|
this.state = { hasError: false, error: null }
|
|
}
|
|
|
|
static getDerivedStateFromError(error: Error): State {
|
|
return { hasError: true, error }
|
|
}
|
|
|
|
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
|
|
console.error('ErrorBoundary caught an error:', error, errorInfo)
|
|
}
|
|
|
|
handleReset = (): void => {
|
|
this.setState({ hasError: false, error: null })
|
|
}
|
|
|
|
render(): ReactNode {
|
|
if (this.state.hasError) {
|
|
if (this.props.fallback) {
|
|
return this.props.fallback
|
|
}
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
height: '100vh',
|
|
padding: '2rem',
|
|
textAlign: 'center',
|
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
}}
|
|
>
|
|
<h2 style={{ marginBottom: '1rem', color: '#e74c3c' }}>
|
|
应用遇到了错误
|
|
</h2>
|
|
<pre
|
|
style={{
|
|
padding: '1rem',
|
|
backgroundColor: '#f8f9fa',
|
|
borderRadius: '8px',
|
|
maxWidth: '600px',
|
|
overflow: 'auto',
|
|
fontSize: '0.875rem',
|
|
color: '#666',
|
|
}}
|
|
>
|
|
{this.state.error?.message}
|
|
</pre>
|
|
<button
|
|
onClick={this.handleReset}
|
|
style={{
|
|
marginTop: '1rem',
|
|
padding: '0.5rem 1.5rem',
|
|
border: 'none',
|
|
borderRadius: '6px',
|
|
backgroundColor: '#3498db',
|
|
color: 'white',
|
|
cursor: 'pointer',
|
|
fontSize: '1rem',
|
|
}}
|
|
>
|
|
重试
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return this.props.children
|
|
}
|
|
}
|