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

Next.js集成Storyblok React Bridge预览iframe异常重启问题

问题描述

在Next.js项目中使用新版Storyblok React bridge时,_app.js中存在一个路由切换时不会卸载的固定组件,相关代码如下:

function MyApp({ Component, pageProps: { pageData, globalData } }) {
  const story = useStoryblokState(globalData.story)
  console.log('rendering app')
  return (
    <>
      <Collage story={story} />
      {/* <Component {...pageData} /> */}
    </>
  );
}

对应的getStaticProps代码如下:

export async function getStaticProps() {
  let sbParams = {
    version: "draft", // or 'published'
  };

  const storyblokApi = getStoryblokApi();
  let { data: pageData } = await storyblokApi.get(`cdn/stories/home`, sbParams);
  let { data: globalData } = await storyblokApi.get(
    `cdn/stories/collage`,
    sbParams
  );

  return {
    props: {
      pageData,
      globalData,
    },
    revalidate: 3600,
  };
}

注释主组件时功能符合预期:数据变更只会触发Collage组件重渲染,不会触发整页刷新。但取消主组件注释后,在Storyblok预览环境(对接localhost:3000本地服务)中修改任意数据都会导致iFrame重启,表现和未接入React bridge时完全一致,且iFrame重启前数据变更已经实际生效。

问题根因

触发这个问题的核心原因有两点:

  • 仅给全局Collage组件对应的globalData.story添加了useStoryblokState订阅,页面组件Component接收的pageData.story没有接入桥接订阅。新版Storyblok React bridge检测到渲染树中存在未被订阅的Storyblok story数据时,会判定页面没有完成全量实时更新绑定,直接触发iframe硬重载拉取最新内容,保证预览效果和编辑器配置一致。
  • useStoryblokState直接写在_app.js根组件中,每次story更新会触发整个应用根组件重渲染,导致页面组件状态被重置,和bridge的状态监听逻辑产生冲突,也会触发热更新失效、iframe重载。
修复方案

按以下步骤调整即可解决:

  • 把全局固定组件的useStoryblokState订阅逻辑从_app.js根组件拆到独立的子组件中,避免根组件重渲染影响整个渲染树的状态
  • 给页面组件对应的story数据也统一添加useStoryblokState订阅,保证所有传入渲染树的Storyblok story数据都被bridge接管

调整后的参考代码如下:
首先修改_app.js,移除根组件中的hook调用,拆分独立的全局组件容器和页面渲染容器:

// 独立封装全局固定的Collage组件,单独处理订阅逻辑
function GlobalCollage({ storyData }) {
  const story = useStoryblokState(storyData)
  return <Collage story={story} />
}

// 统一封装页面组件渲染逻辑,处理页面story的订阅
function PageRenderer({ pageData, Component }) {
  const pageStory = useStoryblokState(pageData.story)
  // 保持传给页面组件的props结构和之前一致
  const resolvedProps = {
    ...pageData,
    story: pageStory
  }
  return <Component {...resolvedProps} />
}

function MyApp({ Component, pageProps: { pageData, globalData } }) {
  return (
    <>
      <GlobalCollage storyData={globalData.story} />
      <PageRenderer pageData={pageData} Component={Component} />
    </>
  );
}

多页面项目不需要给每个页面单独写订阅逻辑,用上面的统一PageRenderer封装即可。
如果调整后仍然出现iframe重载,检查Storyblok初始化配置,确保bridge功能没有被关闭:

import { storyblokInit, apiPlugin } from "@storyblok/react";

storyblokInit({
  accessToken: "项目对应的access token",
  use: [apiPlugin],
  bridge: true, // 不要把这个配置设为false
  components: {
    // 项目注册的所有Storyblok块组件
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 12:48:18