You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js应用中Prisma复杂查询的拆分与标准化方案

针对Next.js Todo信息流数据结构不一致的优化方案

1. 标准化数据结构(核心解决方案)

统一todos及关联字段的结构是避免重复适配的关键:

  • 优先推动后端统一接口返回格式:要求getRecentTodos和getUserDetailsByName返回的todos数组结构完全一致,比如todoReplies必须包含displayName字段,缺失时返回默认值(如'匿名用户')。
  • 若后端无法快速修改,在前端新增数据转换层,将不同接口的响应统一转换成组件期望的格式:
    // 定义组件依赖的标准Todo类型
    type Todo = {
      id: string;
      content: string;
      todoReplies: {
        id: string;
        displayName: string;
        content: string;
      }[];
      // 其他必填字段
    };
    
    // 转换首页接口返回的数据
    const transformRecentTodos = (rawData: unknown): Todo[] => {
      const parsedData = rawData as { todos: any[] };
      return parsedData.todos.map(todo => ({
        ...todo,
        todoReplies: (todo.replies || []).map(reply => ({
          id: reply.id,
          displayName: reply.userName || '匿名用户', // 映射差异字段
          content: reply.content
        }))
      }));
    };
    
    // 转换用户页接口返回的数据
    const transformUserTodos = (rawData: unknown): Todo[] => {
      const parsedData = rawData as { user: { todos: any[] } };
      return parsedData.user.todos.map(todo => ({
        ...todo,
        todoReplies: (todo.commentReplies || []).map(reply => ({
          id: reply.id,
          displayName: reply.displayName || '匿名用户',
          content: reply.content
        }))
      }));
    };
    
    在getServerSideProps中调用转换函数,将标准化后的数据传递给组件。

2. TypeScript强校验,提前发现结构问题

通过类型系统和运行时校验,避免因结构差异导致的线上问题:

  • 复用统一的Todo类型,确保所有数据处理逻辑都遵循该类型定义。
  • 用zod等工具做运行时校验,在数据转换后验证结构是否符合预期:
    import { z } from 'zod';
    
    // 定义严格的Schema
    const TodoReplySchema = z.object({
      id: z.string(),
      displayName: z.string().default('匿名用户'),
      content: z.string()
    });
    
    const TodoSchema = z.object({
      id: z.string(),
      content: z.string(),
      todoReplies: z.array(TodoReplySchema)
    });
    
    // 在getServerSideProps中校验数据
    export async function getServerSideProps() {
      const rawData = await getRecentTodos();
      const normalizedTodos = transformRecentTodos(rawData);
      // 校验失败直接抛出错误,开发阶段即可发现问题
      const validatedTodos = TodoSchema.array().parse(normalizedTodos);
      return { props: { todos: validatedTodos } };
    }
    

3. 拆分请求逻辑,降低耦合度

把todo数据的获取、转换逻辑封装成通用模块,减少重复代码:

  • 封装通用的fetchAndNormalizeTodos函数,统一处理请求和数据转换:
    async function fetchAndNormalizeTodos(
      fetcher: () => Promise<unknown>,
      transformer: (data: unknown) => Todo[]
    ): Promise<Todo[]> {
      const rawData = await fetcher();
      const normalizedTodos = transformer(rawData);
      return TodoSchema.array().parse(normalizedTodos);
    }
    
    // 首页的getServerSideProps
    export async function getServerSideProps() {
      const todos = await fetchAndNormalizeTodos(getRecentTodos, transformRecentTodos);
      return { props: { todos } };
    }
    
    // 用户页的getServerSideProps
    export async function getServerSideProps(context) {
      const userName = context.params.userName as string;
      const todos = await fetchAndNormalizeTodos(
        () => getUserDetailsByName(userName),
        transformUserTodos
      );
      return { props: { todos } };
    }
    
  • 将Todo渲染组件设计为纯组件,仅依赖标准Todo类型,不关心数据来源,确保组件的通用性。

4. 长期维护建议

  • 和后端团队对齐接口规范,将todos的标准结构写入接口文档,避免后续新增接口出现结构分歧。
  • 新增接口时,复用已有的类型定义和转换逻辑,禁止新增独立的适配代码。
  • 后端统一结构后,及时移除前端的转换逻辑,减少冗余代码。

内容的提问来源于stack exchange,提问作者Martei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:25:46