@qlover/create-app 0.7.14 → 0.7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/next-app/README.en.md +131 -0
  5. package/dist/templates/next-app/README.md +115 -20
  6. package/dist/templates/next-app/docs/en/api.md +387 -0
  7. package/dist/templates/next-app/docs/en/component.md +544 -0
  8. package/dist/templates/next-app/docs/en/database.md +496 -0
  9. package/dist/templates/next-app/docs/en/development-guide.md +727 -0
  10. package/dist/templates/next-app/docs/en/env.md +563 -0
  11. package/dist/templates/next-app/docs/en/i18n.md +287 -0
  12. package/dist/templates/next-app/docs/en/index.md +166 -0
  13. package/dist/templates/next-app/docs/en/page.md +457 -0
  14. package/dist/templates/next-app/docs/en/project-structure.md +177 -0
  15. package/dist/templates/next-app/docs/en/router.md +427 -0
  16. package/dist/templates/next-app/docs/en/theme.md +532 -0
  17. package/dist/templates/next-app/docs/en/validator.md +478 -0
  18. package/dist/templates/next-app/docs/zh/api.md +387 -0
  19. package/dist/templates/next-app/docs/zh/component.md +544 -0
  20. package/dist/templates/next-app/docs/zh/database.md +496 -0
  21. package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
  22. package/dist/templates/next-app/docs/zh/env.md +563 -0
  23. package/dist/templates/next-app/docs/zh/i18n.md +287 -0
  24. package/dist/templates/next-app/docs/zh/index.md +166 -0
  25. package/dist/templates/next-app/docs/zh/page.md +457 -0
  26. package/dist/templates/next-app/docs/zh/project-structure.md +177 -0
  27. package/dist/templates/next-app/docs/zh/router.md +427 -0
  28. package/dist/templates/next-app/docs/zh/theme.md +532 -0
  29. package/dist/templates/next-app/docs/zh/validator.md +476 -0
  30. package/package.json +1 -1
  31. package/dist/templates/next-app/docs/env.md +0 -94
@@ -0,0 +1,544 @@
1
+ # 组件开发和状态管理指南
2
+
3
+ ## 目录
4
+
5
+ 1. [组件架构概述](#组件架构概述)
6
+ 2. [组件架构和设计原则](#组件架构和设计原则)
7
+ 3. [状态管理系统](#状态管理系统)
8
+ 4. [组件通信和事件处理](#组件通信和事件处理)
9
+ 5. [组件测试和性能优化](#组件测试和性能优化)
10
+ 6. [最佳实践和示例](#最佳实践和示例)
11
+
12
+ ## 组件架构概述
13
+
14
+ ### 1. 整体架构
15
+
16
+ 项目采用分层的组件架构设计:
17
+
18
+ ```
19
+ 组件层 状态层
20
+ ┌──────────────┐ ┌──────────────┐
21
+ │ UI 组件 │ │ 状态接口 │
22
+ ├──────────────┤ ├──────────────┤
23
+ │ 容器组件 │ ◄─────┤ 状态实现 │
24
+ ├──────────────┤ ├──────────────┤
25
+ │ 业务组件 │ │ 状态动作 │
26
+ └──────────────┘ └──────────────┘
27
+ ```
28
+
29
+ ### 2. 核心概念
30
+
31
+ - **UI 组件**:纯展示组件,不包含业务逻辑
32
+ - **容器组件**:负责状态管理和业务逻辑
33
+ - **业务组件**:特定业务场景的组件
34
+ - **状态管理**:基于 Store 模式的状态管理系统
35
+
36
+ ### 3. 技术栈
37
+
38
+ - **React + Next.js**:基础框架
39
+ - **TypeScript**:类型系统
40
+ - **Inversify**:依赖注入
41
+ - **Ant Design**:UI 组件库
42
+ - **Tailwind CSS**:样式系统
43
+
44
+ ## 组件架构和设计原则
45
+
46
+ ### 1. 组件分类
47
+
48
+ ```typescript
49
+ // 1. UI 组件
50
+ export function Button({ onClick, children }: ButtonProps) {
51
+ return (
52
+ <button
53
+ onClick={onClick}
54
+ className="px-4 py-2 bg-primary text-white rounded"
55
+ >
56
+ {children}
57
+ </button>
58
+ );
59
+ }
60
+
61
+ // 2. 容器组件
62
+ export function UserProfileContainer() {
63
+ const userStore = useIOC(UserStore);
64
+ const user = useStore(userStore, userStore.selector.user);
65
+
66
+ return <UserProfile user={user} />;
67
+ }
68
+
69
+ // 3. 业务组件
70
+ export function LoginForm({ tt }: { tt: LoginI18nInterface }) {
71
+ const userService = useIOC(I.UserServiceInterface);
72
+
73
+ const handleLogin = async (values: LoginFormData) => {
74
+ await userService.login(values);
75
+ };
76
+
77
+ return (
78
+ <Form onFinish={handleLogin}>
79
+ {/* 表单内容 */}
80
+ </Form>
81
+ );
82
+ }
83
+ ```
84
+
85
+ ### 2. 组件提供者
86
+
87
+ ```typescript
88
+ // 组合多个提供者
89
+ export function ComboProvider({
90
+ themeConfig,
91
+ children
92
+ }: Props) {
93
+ const mounted = useMountedClient();
94
+ const IOC = clientIOC.create();
95
+
96
+ return (
97
+ <AntdThemeProvider theme={themeConfig.antdTheme}>
98
+ <ThemeProvider
99
+ themes={themeConfig.supportedThemes}
100
+ defaultTheme={themeConfig.defaultTheme}
101
+ >
102
+ <BootstrapsProvider>
103
+ <AntdRegistry>
104
+ {mounted ? children : null}
105
+ </AntdRegistry>
106
+ </BootstrapsProvider>
107
+ </ThemeProvider>
108
+ </AntdThemeProvider>
109
+ );
110
+ }
111
+ ```
112
+
113
+ ### 3. 组件接口设计
114
+
115
+ ```typescript
116
+ // 1. 组件接口定义
117
+ interface ChatComponentInterface {
118
+ // 属性定义
119
+ messages: MessageInterface[];
120
+ loading?: boolean;
121
+
122
+ // 事件处理
123
+ onSend: (message: string) => void;
124
+ onClear: () => void;
125
+ }
126
+
127
+ // 2. 组件实现
128
+ @injectable()
129
+ export class ChatComponent implements ChatComponentInterface {
130
+ constructor(
131
+ @inject(ChatStore) private store: ChatStoreInterface,
132
+ @inject(I.Logger) private logger: LoggerInterface
133
+ ) {}
134
+
135
+ // 实现接口方法
136
+ async onSend(message: string) {
137
+ try {
138
+ await this.store.sendMessage(message);
139
+ } catch (error) {
140
+ this.logger.error('Failed to send message:', error);
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## 状态管理系统
147
+
148
+ ### 1. 状态接口
149
+
150
+ ```typescript
151
+ // 1. 状态接口定义
152
+ export interface StoreStateInterface {
153
+ readonly loading?: boolean;
154
+ readonly error?: Error | null;
155
+ }
156
+
157
+ // 2. 异步状态接口
158
+ export interface AsyncStateInterface<T> {
159
+ loading: boolean;
160
+ result: T | null;
161
+ error: unknown | null;
162
+ startTime: number;
163
+ endTime: number;
164
+ }
165
+
166
+ // 3. 请求状态实现
167
+ export class RequestState<T = unknown> implements AsyncStateInterface<T> {
168
+ startTime: number;
169
+ endTime: number;
170
+
171
+ constructor(
172
+ public loading: boolean = false,
173
+ public result: T | null = null,
174
+ public error: unknown | null = null
175
+ ) {
176
+ this.startTime = Date.now();
177
+ this.endTime = 0;
178
+ }
179
+
180
+ end(): this {
181
+ this.endTime = Date.now();
182
+ return this;
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### 2. Store 实现
188
+
189
+ ```typescript
190
+ // 1. Store 基类
191
+ export abstract class StoreInterface<State extends StoreStateInterface> {
192
+ protected state: State;
193
+ protected subscribers: Set<(state: State) => void>;
194
+
195
+ constructor(initialState: () => State) {
196
+ this.state = initialState();
197
+ this.subscribers = new Set();
198
+ }
199
+
200
+ // 状态更新
201
+ protected emit(newState: State): void {
202
+ this.state = newState;
203
+ this.subscribers.forEach((subscriber) => subscriber(this.state));
204
+ }
205
+
206
+ // 选择器
207
+ selector = {
208
+ loading: (state: State) => state.loading,
209
+ error: (state: State) => state.error
210
+ };
211
+ }
212
+
213
+ // 2. 具体 Store 实现
214
+ @injectable()
215
+ export class UserStore extends StoreInterface<UserState> {
216
+ constructor(@inject(UserService) private userService: UserServiceInterface) {
217
+ super(() => ({
218
+ user: null,
219
+ loading: false,
220
+ error: null
221
+ }));
222
+ }
223
+
224
+ async fetchUser(id: string) {
225
+ this.emit({ ...this.state, loading: true });
226
+ try {
227
+ const user = await this.userService.getUser(id);
228
+ this.emit({ ...this.state, user, loading: false });
229
+ } catch (error) {
230
+ this.emit({ ...this.state, error, loading: false });
231
+ }
232
+ }
233
+ }
234
+ ```
235
+
236
+ ### 3. 状态使用
237
+
238
+ ```typescript
239
+ // 1. 在组件中使用 Store
240
+ export function UserProfile() {
241
+ const userStore = useIOC(UserStore);
242
+ const user = useStore(userStore, userStore.selector.user);
243
+ const loading = useStore(userStore, userStore.selector.loading);
244
+
245
+ useEffect(() => {
246
+ userStore.fetchUser(userId);
247
+ }, [userStore, userId]);
248
+
249
+ if (loading) return <Loading />;
250
+ if (!user) return <NotFound />;
251
+
252
+ return <UserInfo user={user} />;
253
+ }
254
+
255
+ // 2. 组合多个 Store
256
+ export function Dashboard() {
257
+ const userStore = useIOC(UserStore);
258
+ const statsStore = useIOC(StatsStore);
259
+
260
+ const user = useStore(userStore, userStore.selector.user);
261
+ const stats = useStore(statsStore, statsStore.selector.stats);
262
+
263
+ return (
264
+ <div>
265
+ <UserWidget user={user} />
266
+ <StatsWidget stats={stats} />
267
+ </div>
268
+ );
269
+ }
270
+ ```
271
+
272
+ ## 组件通信和事件处理
273
+
274
+ ### 1. 事件处理
275
+
276
+ ```typescript
277
+ // 1. 定义事件接口
278
+ interface ChatEvents {
279
+ onSend: (message: string) => void;
280
+ onClear: () => void;
281
+ onError: (error: Error) => void;
282
+ }
283
+
284
+ // 2. 实现事件处理
285
+ export function ChatComponent({ onSend, onClear, onError }: ChatEvents) {
286
+ const handleSend = useCallback(async (message: string) => {
287
+ try {
288
+ await onSend(message);
289
+ } catch (error) {
290
+ onError(error as Error);
291
+ }
292
+ }, [onSend, onError]);
293
+
294
+ return (
295
+ <div>
296
+ <ChatInput onSend={handleSend} />
297
+ <ClearButton onClick={onClear} />
298
+ </div>
299
+ );
300
+ }
301
+ ```
302
+
303
+ ### 2. 组件通信
304
+
305
+ ```typescript
306
+ // 1. 通过属性传递
307
+ export function ParentComponent() {
308
+ const [data, setData] = useState<Data>();
309
+
310
+ return (
311
+ <ChildComponent
312
+ data={data}
313
+ onUpdate={setData}
314
+ />
315
+ );
316
+ }
317
+
318
+ // 2. 通过 Context 共享
319
+ const ThemeContext = createContext<Theme>(defaultTheme);
320
+
321
+ export function ThemeProvider({ children }: PropsWithChildren) {
322
+ const [theme, setTheme] = useState(defaultTheme);
323
+
324
+ return (
325
+ <ThemeContext.Provider value={{ theme, setTheme }}>
326
+ {children}
327
+ </ThemeContext.Provider>
328
+ );
329
+ }
330
+ ```
331
+
332
+ ## 组件测试和性能优化
333
+
334
+ ### 1. 组件测试
335
+
336
+ ```typescript
337
+ // 1. 单元测试
338
+ describe('UserProfile', () => {
339
+ it('should render user info', () => {
340
+ const user = { id: '1', name: 'Test' };
341
+ render(<UserProfile user={user} />);
342
+
343
+ expect(screen.getByText(user.name)).toBeInTheDocument();
344
+ });
345
+
346
+ it('should handle loading state', () => {
347
+ render(<UserProfile loading />);
348
+ expect(screen.getByTestId('loading')).toBeInTheDocument();
349
+ });
350
+ });
351
+
352
+ // 2. 集成测试
353
+ describe('LoginForm', () => {
354
+ it('should handle login flow', async () => {
355
+ const mockLogin = jest.fn();
356
+ const { getByLabelText, getByRole } = render(
357
+ <LoginForm onLogin={mockLogin} />
358
+ );
359
+
360
+ await userEvent.type(getByLabelText('Email'), 'test@example.com');
361
+ await userEvent.type(getByLabelText('Password'), 'password');
362
+ await userEvent.click(getByRole('button', { name: 'Login' }));
363
+
364
+ expect(mockLogin).toHaveBeenCalledWith({
365
+ email: 'test@example.com',
366
+ password: 'password'
367
+ });
368
+ });
369
+ });
370
+ ```
371
+
372
+ ### 2. 性能优化
373
+
374
+ ```typescript
375
+ // 1. 使用 memo 优化渲染
376
+ const UserCard = memo(function UserCard({ user }: UserCardProps) {
377
+ return (
378
+ <div>
379
+ <h3>{user.name}</h3>
380
+ <p>{user.email}</p>
381
+ </div>
382
+ );
383
+ });
384
+
385
+ // 2. 使用 useMemo 和 useCallback
386
+ function UserList({ users }: UserListProps) {
387
+ const sortedUsers = useMemo(() => {
388
+ return [...users].sort((a, b) => a.name.localeCompare(b.name));
389
+ }, [users]);
390
+
391
+ const handleUserClick = useCallback((userId: string) => {
392
+ // 处理用户点击
393
+ }, []);
394
+
395
+ return (
396
+ <div>
397
+ {sortedUsers.map(user => (
398
+ <UserCard
399
+ key={user.id}
400
+ user={user}
401
+ onClick={handleUserClick}
402
+ />
403
+ ))}
404
+ </div>
405
+ );
406
+ }
407
+ ```
408
+
409
+ ## 最佳实践和示例
410
+
411
+ ### 1. 组件设计原则
412
+
413
+ ```typescript
414
+ // 1. 单一职责原则
415
+ // ❌ 错误:组件职责过多
416
+ function UserCard({ user, onEdit, onDelete, onShare }) {
417
+ return (
418
+ <div>
419
+ <UserInfo user={user} />
420
+ <UserActions user={user} />
421
+ <SocialSharing user={user} />
422
+ </div>
423
+ );
424
+ }
425
+
426
+ // ✅ 正确:拆分为多个专注的组件
427
+ function UserCard({ user }) {
428
+ return <UserInfo user={user} />;
429
+ }
430
+
431
+ function UserActions({ user }) {
432
+ return (
433
+ <div>
434
+ <EditButton user={user} />
435
+ <DeleteButton user={user} />
436
+ </div>
437
+ );
438
+ }
439
+
440
+ // 2. 组合优于继承
441
+ // ❌ 错误:使用继承
442
+ class SpecialButton extends Button {
443
+ render() {
444
+ return <button className="special">{this.props.children}</button>;
445
+ }
446
+ }
447
+
448
+ // ✅ 正确:使用组合
449
+ function Button({ variant, children, ...props }) {
450
+ return (
451
+ <button className={`btn-${variant}`} {...props}>
452
+ {children}
453
+ </button>
454
+ );
455
+ }
456
+ ```
457
+
458
+ ### 2. 状态管理最佳实践
459
+
460
+ ```typescript
461
+ // 1. 状态隔离
462
+ @injectable()
463
+ export class UserStore extends StoreInterface<UserState> {
464
+ // 将状态逻辑封装在 Store 中
465
+ private async validateUser(user: User): Promise<boolean> {
466
+ return this.validator.validate(user);
467
+ }
468
+
469
+ async updateUser(user: User) {
470
+ if (await this.validateUser(user)) {
471
+ this.emit({ ...this.state, user });
472
+ }
473
+ }
474
+ }
475
+
476
+ // 2. 选择器模式
477
+ @injectable()
478
+ export class DashboardStore extends StoreInterface<DashboardState> {
479
+ selector = {
480
+ ...super.selector,
481
+ activeUsers: (state: DashboardState) =>
482
+ state.users.filter((u) => u.isActive),
483
+ totalRevenue: (state: DashboardState) =>
484
+ state.transactions.reduce((sum, t) => sum + t.amount, 0)
485
+ };
486
+ }
487
+ ```
488
+
489
+ ### 3. 性能优化示例
490
+
491
+ ```typescript
492
+ // 1. 虚拟列表
493
+ function VirtualizedList({ items }: Props) {
494
+ return (
495
+ <VirtualScroller
496
+ itemCount={items.length}
497
+ itemSize={50}
498
+ height={400}
499
+ width="100%"
500
+ >
501
+ {({ index, style }) => (
502
+ <div style={style}>
503
+ <ListItem item={items[index]} />
504
+ </div>
505
+ )}
506
+ </VirtualScroller>
507
+ );
508
+ }
509
+
510
+ // 2. 懒加载组件
511
+ const LazyUserProfile = lazy(() => import('./UserProfile'));
512
+
513
+ function App() {
514
+ return (
515
+ <Suspense fallback={<Loading />}>
516
+ <LazyUserProfile />
517
+ </Suspense>
518
+ );
519
+ }
520
+ ```
521
+
522
+ ## 总结
523
+
524
+ 项目的组件和状态管理系统遵循以下原则:
525
+
526
+ 1. **组件设计**:
527
+ - 清晰的职责划分
528
+ - 可复用的组件接口
529
+ - 类型安全的属性定义
530
+
531
+ 2. **状态管理**:
532
+ - 集中的状态管理
533
+ - 响应式的状态更新
534
+ - 类型安全的状态定义
535
+
536
+ 3. **性能优化**:
537
+ - 组件级别的优化
538
+ - 状态更新的优化
539
+ - 资源加载的优化
540
+
541
+ 4. **最佳实践**:
542
+ - 单一职责原则
543
+ - 组合优于继承
544
+ - 状态隔离原则