9-frontend-architecture.md 2.9 KB

9. Frontend Architecture

定义前端特定的架构细节:

9.1 组件架构

组件组织

src/
├── components/
│   ├── ui/                    # 基础UI组件(可复用)
│   ├── forms/                 # 表单组件
│   ├── layout/                # 布局组件
│   └── features/              # 功能组件

组件模板

// components/ui/button/Button.tsx
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
  size?: 'default' | 'sm' | 'lg' | 'icon';
}

const Button = forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant = 'default', size = 'default', ...props }, ref) => {
  return (
    <button
      className={cn(
        'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors',
        // ...样式类
      )}
      ref={ref}
      {...props}
    />
  );
});

9.2 状态管理架构

状态结构

// stores/auth-store.ts
export const useAuthStore = create<AuthState>((set, get) => ({
  user: null,
  token: localStorage.getItem('token'),
  isLoading: false,

  login: async (email: string, password: string) => {
    set({ isLoading: true });
    try {
      const response = await apiClient.auth.login.$post({ json: { email, password } });
      const { user, token } = await response.json();

      localStorage.setItem('token', token);
      set({ user, token, isLoading: false });
    } catch (error) {
      set({ isLoading: false });
      throw error;
    }
  },
}));

9.3 路由架构

路由组织

// routes/index.tsx
export const router = createBrowserRouter([
  {
    path: '/auth',
    element: <AuthLayout />,
    children: [
      { path: 'login', element: <LoginPage /> },
    ],
  },
  {
    path: '/',
    element: <AppLayout />,
    children: [
      { index: true, element: <DashboardPage /> },
      { path: 'users', element: <UsersPage /> },
    ],
  },
]);

保护路由模式

// components/auth/ProtectedRoute.tsx
export function ProtectedRoute({ children }: ProtectedRouteProps) {
  const { user, isLoading, initialize } = useAuthStore();
  const navigate = useNavigate();

  useEffect(() => {
    if (!isLoading && !user) {
      navigate('/auth/login');
    }
  }, [user, isLoading, navigate]);

  return user ? <>{children}</> : null;
}

9.4 前端服务层

API客户端设置

// lib/api-client.ts
export const apiClient = hc<AppType>(import.meta.env.VITE_API_URL || 'http://localhost:8080');

// 请求拦截器 - 自动添加token
apiClient._fetch = async (input, init) => {
  const token = localStorage.getItem('token');
  const headers = new Headers(init?.headers);

  if (token) {
    headers.set('Authorization', `Bearer ${token}`);
  }

  return fetch(input, { ...init, headers });
};