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

Next.js router.query行为不一致问题及解决方法咨询

解决Next.js动态路由slug旧值导致请求错误的问题

问题根源

你的代码里fetchPhotos直接引用外部的slug变量,路由切换时闭包会捕获旧的slug值,导致请求用错参数。另外useEffect的依赖只加了slug,没包含router.isReady,可能在路由未完全就绪时就触发请求,进一步加剧参数不一致的问题。

修复方案

方案1:将slug作为参数传入fetchPhotos,避免闭包陷阱

修改fetchPhotos让它接收slug作为参数,每次调用时传入最新值,确保请求用的是当前路由的参数:

const router = useRouter();
const { slug } = router.query;

useEffect(() => {
  if (router.isReady && slug) {
    fetchPhotos(slug);
  }
}, [router.isReady, slug]) // 添加router.isReady到依赖项

const fetchPhotos = (currentSlug) => {
  unsplash.search.getPhotos({
    query: currentSlug, // 使用传入的最新slug
    page: 1,
    perPage,
  })
  .then((result) => {
    if (result.status === 200 && result.type === "success") {
      dispatch({ type: "SET_PHOTOS", payload: result.response.result })
    } 
    else {
      console.log(result.errors);
    }
  })
  .catch((info) => {
    console.log(info);
  });
};

方案2:监听路由完成事件,确保获取最新参数

利用Next.js Router的routeChangeComplete事件,在路由完全切换后再获取最新slug并触发请求:

const router = useRouter();

useEffect(() => {
  const handleRouteChange = () => {
    const { slug } = router.query;
    if (slug) {
      fetchPhotos(slug);
    }
  };

  // 监听路由切换完成事件
  router.events.on('routeChangeComplete', handleRouteChange);

  // 组件卸载时移除监听
  return () => {
    router.events.off('routeChangeComplete', handleRouteChange);
  };
}, [router])

const fetchPhotos = (currentSlug) => {
  unsplash.search.getPhotos({
    query: currentSlug,
    page: 1,
    perPage,
  })
  .then((result) => {
    if (result.status === 200 && result.type === "success") {
      dispatch({ type: "SET_PHOTOS", payload: result.response.result })
    } 
    else {
      console.log(result.errors);
    }
  })
  .catch((info) => {
    console.log(info);
  });
};

方案3:直接从router.query获取最新值

在fetchPhotos里直接读取router.query.slug,同时确保useEffect依赖包含router.isReady和router.query.slug:

const router = useRouter();

useEffect(() => {
  if (router.isReady && router.query.slug) {
    fetchPhotos();
  }
}, [router.isReady, router.query.slug])

const fetchPhotos = () => {
  const currentSlug = router.query.slug; // 直接从router.query取最新值
  unsplash.search.getPhotos({
    query: currentSlug,
    page: 1,
    perPage,
  })
  .then((result) => {
    if (result.status === 200 && result.type === "success") {
      dispatch({ type: "SET_PHOTOS", payload: result.response.result })
    } 
    else {
      console.log(result.errors);
    }
  })
  .catch((info) => {
    console.log(info);
  });
};

关键说明

  • 闭包陷阱是核心问题:组件渲染时fetchPhotos会捕获当时的slug值,路由切换后如果旧的请求还在执行,就会继续用旧值。把slug作为参数传入能彻底避免这个问题。
  • 必须检查router.isReady:确保路由参数完全加载完成后再触发请求,避免slug为undefined或旧值的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:42:16