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

NextJS动态路由无法解析GraphQL异步请求排查求助

Next.js动态路由用户查询问题修复

问题场景

设置localhost:3000/[username]形式的动态路由,通过GraphQL查询MongoDB:存在的用户名正常显示,不存在则提示“User {slug} Not Found”。已验证GraphQL查询逻辑(调用getUser()时,有效用户返回对象,无效用户返回null),但发现useEffect中的fetchData()从未执行(console.log无输出),怀疑异步方法使用错误。


原始代码

页面组件代码

import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { getUser } from '@/lib/users';
import {subscribe} from "graphql";

const UserPage = () => {
  const router = useRouter();
  const { slug } = router.query;
  const [isValidUser, setIsValidUser] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      console.log(fetchData)
      let result;
      if (slug === undefined || slug == null) {
        result = null;
      } else {
        result = Array.isArray(slug) ? slug[0] : slug;
        const user = await getUser(result);
        if (user) {
          setIsValidUser(true);
        }
      }
      return result;
    }


    if (slug) {
      fetchData().catch(console.error);
    }
  }, [slug]);

  return (
    <>
      {isValidUser ? (
        <p>User {slug} found!</p>
      ) : (
        <p>User {slug} not found.</p>
      )}
    </>
  );
};

export default UserPage;

getUser GraphQL查询代码

import { apolloClient } from "@/pages/_app";
import { GET_USER_BY_USERNAME_OR_ADDRESS } from "../db/queries/userQueries";
import { ADD_USER } from "../db/mutations/userMutations";

const GET_USER_BY_USERNAME_OR_ADDRESS = gql`
  query GetUserByUsernameOrAddress($usernameOrAddress: String) {
    getUserByUsernameOrAddress(usernameOrAddress: $usernameOrAddress) {
      address
      bio
      username
    }
  }
`;

const getUser = async (addressOrUsername: string) => {
  try {
    const { data } = await apolloClient.query({
      query: GET_USER_BY_USERNAME_OR_ADDRESS,
      variables: { addressOrUsername },
    });
    if ( data ){
      return data;
    } else {
      return null;
    }
  } catch (error) {
    console.error(error);
  }
  return false;
};

问题排查与修复

1. fetchData未执行的核心原因

Next.js客户端路由初始化时,router.query.slug初始值为undefined,此时useEffect触发但if (slug)条件不成立,fetchData不会执行。同时原日志写法错误(console.log(fetchData)打印函数本身而非执行日志),会误导判断函数是否执行。

2. 分步修复

(1)修正路由就绪判断与日志

添加router.isReady判断确保路由参数完全加载,同时修正日志内容:

useEffect(() => {
  const fetchData = async () => {
    console.log('执行fetchData,当前slug:', slug); // 修正日志
    let targetSlug = Array.isArray(slug) ? slug[0] : slug;
    const user = await getUser(targetSlug);
    setIsValidUser(!!user); // 直接转换为布尔值
  };

  // 等待路由就绪且slug存在时执行查询
  if (router.isReady && slug) {
    fetchData().catch(console.error);
  }
}, [router.isReady, slug]);

(2)修复getUser返回值逻辑

原代码返回整个data对象,即使用户不存在,data本身仍存在,导致if (user)判断始终为true。应返回具体查询字段:

const getUser = async (addressOrUsername: string) => {
  try {
    const { data } = await apolloClient.query({
      query: GET_USER_BY_USERNAME_OR_ADDRESS,
      variables: { addressOrUsername },
    });
    // 返回具体用户数据,不存在则为null
    return data.getUserByUsernameOrAddress || null;
  } catch (error) {
    console.error('查询用户失败:', error);
    return null; // 错误时统一返回null
  }
};

(3)添加加载状态优化体验

避免初始页面显示User undefined not found,新增加载状态:

const UserPage = () => {
  const router = useRouter();
  const { slug } = router.query;
  const [isValidUser, setIsValidUser] = useState(false);
  const [isLoading, setIsLoading] = useState(true); // 新增加载状态

  useEffect(() => {
    const fetchData = async () => {
      setIsLoading(true);
      let targetSlug = Array.isArray(slug) ? slug[0] : slug;
      const user = await getUser(targetSlug);
      setIsValidUser(!!user);
      setIsLoading(false);
    };

    if (router.isReady && slug) {
      fetchData().catch(console.error);
    } else {
      setIsLoading(false);
    }
  }, [router.isReady, slug]);

  if (isLoading) {
    return <p>Loading...</p>;
  }

  return (
    <>
      {isValidUser ? (
        <p>User {slug} found!</p>
      ) : (
        <p>User {slug} not found.</p>
      )}
    </>
  );
};

(4)推荐方案:用getServerSideProps预获取数据

Next.js动态路由推荐在服务端预获取数据,避免客户端异步请求延迟:

import { getUser } from '@/lib/users';

const UserPage = ({ user, slug }) => {
  if (!user) {
    return <p>User {slug} not found.</p>;
  }
  return <p>User {slug} found!</p>;
};

export async function getServerSideProps(context) {
  const { slug } = context.params;
  const targetSlug = Array.isArray(slug) ? slug[0] : slug;
  const user = await getUser(targetSlug);

  return {
    props: {
      user,
      slug: targetSlug,
    },
  };
}

export default UserPage;

补充说明:技术栈为NextJS、MongoDB、NextAuth

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:45:02