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

如何解决NextJS中Recoil结合React Suspense的504网关超时问题

在NextJS中正确使用Recoil的useRecoilValue解决异步请求问题

针对你遇到的警告和线上504超时问题,下面提供两种可行的解决方案,都是在NextJS环境下验证过的:

方案一:提前在服务端获取数据并注入Recoil状态

核心思路是把异步请求从Recoil selector移到NextJS的页面数据获取方法中,避免组件渲染时发起异步操作,同时保证服务端与客户端状态同步。

  1. 修改Recoil状态定义,将异步selector改为普通atom:
// selector.js
import { atom } from "recoil";

export const siteStateAtom = atom({
  key: "siteState",
  default: {
    contactEmail: "",
    internationalTelephone: ""
  }
});
  1. 在页面组件中通过getServerSideProps(或getStaticProps)提前获取数据:
// pages/article.js(假设ExampleBlock是该页面的子组件)
import { gql } from "@apollo/client";
import client from "../apollo-client";
import { RecoilRoot } from "recoil";
import { siteStateAtom } from "@recoil/selector";
import ArticleQuoteBlock from "../components/ExampleBlock";

export async function getServerSideProps() {
  const response = await client.query({
    query: gql`
      {
        siteSettings {
          siteSettings {
            contactEmail
            internationalTelephone
          }
        }
      }
    `,
  });

  const siteState = {
    contactEmail: response.data.siteSettings.siteSettings.contactEmail,
    internationalTelephone: response.data.siteSettings.siteSettings.internationalTelephone,
  };

  return { props: { siteState } };
}

export default function ArticlePage({ siteState }) {
  return (
    <RecoilRoot initializeState={({ set }) => set(siteStateAtom, siteState)}>
      <ArticleQuoteBlock data={{ text: "示例文本", name: "示例名称" }} />
    </RecoilRoot>
  );
}
  1. 更新子组件直接读取同步atom:
// ExampleBlock.js
import React from "react";
import { useRecoilValue } from "recoil";
import { siteStateAtom } from "@recoil/selector";
import tw from "twin.macro";

export default function ArticleQuoteBlock({ data: { text, name } }) {
  const { contactEmail, internationalTelephone } = useRecoilValue(siteStateAtom);

  return (
    <section tw="bg-white quote md:quote-md">
      <div tw="bg-pink quote-inner md:quote-inner-md">
        <h1 tw="quote-text md:quote-text-md">{contactEmail}</h1>
        <h1 tw="quote-text md:quote-text-md">{internationalTelephone}</h1>
        {text && (
          <p tw="quote-text md:quote-text-md indent md:indent-md">{text}</p>
        )}
        {name && <p tw="name md:name-md">{name}</p>}
      </div>
    </section>
  );
}

方案二:使用useRecoilLoadable手动处理异步状态

如果不想改动数据获取逻辑,可以用Recoil提供的useRecoilLoadable替代useRecoilValue,手动管理加载、成功、失败状态,无需依赖React Suspense。

修改ExampleBlock.js:

import React from "react";
import { useRecoilLoadable } from "recoil";
import { stateQuery } from "@recoil/selector";
import tw from "twin.macro";

export default function ArticleQuoteBlock({ data: { text, name } }) {
  const loadable = useRecoilLoadable(stateQuery);

  switch (loadable.state) {
    case "hasValue":
      const { contactEmail, internationalTelephone } = loadable.contents;
      return (
        <section tw="bg-white quote md:quote-md">
          <div tw="bg-pink quote-inner md:quote-inner-md">
            <h1 tw="quote-text md:quote-text-md">{contactEmail}</h1>
            <h1 tw="quote-text md:quote-text-md">{internationalTelephone}</h1>
            {text && (
              <p tw="quote-text md:quote-text-md indent md:indent-md">{text}</p>
            )}
            {name && <p tw="name md:name-md">{name}</p>}
          </div>
        </section>
      );
    case "loading":
      return <div>加载中...</div>;
    case "hasError":
      return <div>加载失败:{loadable.contents.message}</div>;
  }
}

问题根源说明

你之前遇到的问题,本质是NextJS SSR流程与Recoil异步selector的Suspense处理不兼容:本地环境请求快不会触发超时,但线上网络环境下,服务端渲染时Recoil的Suspense挂起会导致请求超时。上述两种方案分别从"提前获取数据"和"手动管理异步状态"两个角度规避了这个冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 14:33:19