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

Next.js搭配Preact使用react-spring时点击返回按钮触发TypeError报错

问题根因

这个报错是Preact与react-spring内置Context的卸载逻辑不兼容导致的。React的组件卸载顺序为「先卸载子组件,再销毁上层Context Provider」,但Preact的卸载顺序相反,Provider先被销毁后才执行子组件卸载逻辑,导致react-spring内部消费SpringContext时拿到的值为undefined,触发children解构失败的错误。

可行解决方案

按实现成本从低到高排序:

  • 方案1:升级/降级react-spring版本
    该问题是react-spring v9中期版本的已知兼容问题,最新版本已经针对非React运行时添加了Context值兜底判断,你可以直接升级@react-spring/web到最新稳定版,或降级到v9.4.5及以下的兼容版本即可解决。
  • 方案2:手动添加SpringContext兜底
    在你使用Transition组件的页面外层手动包裹SpringContext.Provider,传入空对象作为兜底值,避免Context为undefined的情况:
    import { SpringContext, Transition, animated } from '@react-spring/web'
    
    // 组件内部return部分修改为:
    return (
      <SpringContext.Provider value={{}}>
        <div className={styles.animationContainer}>
          {/* 你原来的Transition代码保持不变 */}
          <Transition
            native
            unique
            items={currentQuestionFlow.id || 'completed'}
            onFrame={() => window.scroll(0, 0)}
            from={{opacity: 0, transform: `translate3d(${animation.from}, 0 ,0)`}}
            enter={{opacity: 1, transform: `translate3d(${animation.enter}, 0, 0)`}}
            leave={{opacity: 0, transform: `translate3(${animation.leave}, 0, 0)`}}
          >
            {transStyles => (
              <animated.div style={{...transStyles}}>
                <Questions question={label} />
                <UIDisplay DATA={DATA} />
              </animated.div>
            )}
          </Transition>
        </div>
      </SpringContext.Provider>
    )
    
  • 方案3:页面卸载时提前终止动画
    在使用动画的页面添加useEffect钩子,卸载时清空所有react-spring待执行动画,避免卸载阶段触发Context消费逻辑:
    import { stop } from '@react-spring/web'
    import { useEffect } from 'react'
    
    // 组件内添加钩子
    useEffect(() => {
      return () => {
        // 终止所有正在执行的动画
        stop(true)
      }
    }, [])
    
  • 方案4:修改Preact别名配置
    如果你不想修改业务代码,可在Next.js的webpack配置中指定react-spring依赖强制使用原生React,其他依赖依然走Preact兼容:
    // next.config.js
    const withPreact = require('next-plugin-preact');
    
    module.exports = withPreact({
      webpack: (config, { dev }) => {
        if (!dev) {
          config.resolve.alias = {
            ...config.resolve.alias,
            // react-spring相关依赖优先使用原生React
            'react/jsx-runtime': require.resolve('react/jsx-runtime'),
            'react-dom': require.resolve('react-dom'),
          }
        }
        return config
      }
    })
    

所有方案都可以保留Preact的包体积优化能力,不需要切换回全量React。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:45:03