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

Astro+Preact项目使用Material UI报Cannot read 'context'错误求助

Astro + Preact + Material UI: 解决SSR时的Cannot read properties of undefined (reading 'context')错误

问题场景

在基于Preact + TypeScript的Astro项目中引入Material UI的Typography组件时,触发以下错误:

TypeError: Cannot read properties of undefined (reading 'context')
    at exports.useContext
    at useTheme (/node_modules/@mui/system/useThemeWithoutDefault.js:15:30)
    at useTheme (/node_modules/@mui/system/useTheme.js:13:46)
    at Box (/node_modules/@mui/system/createBox.js:30:41)
    at Object.t (/node_modules/preact/compat/dist/compat.js:1:1040)
    at file:///node_modules/preact-render-to-string/dist/index.mjs:1:6332
    at F (file:///node_modules/preact-render-to-string/dist/index.mjs:1:6359)
    at F (file:///node_modules/preact-render-to-string/dist/index.mjs:1:6434)
    at Proxy.S (file:///node_modules/preact-render-to-string/dist/index.mjs:1:4833)
    at Object.renderToStaticMarkup (/node_modules/@astrojs/preact/dist/server.js:55:45)
    at renderFrameworkComponent (/node_modules/astro/dist/runtime/server/render/component.js:187:66)

仅当给组件添加client:only="preact"属性时能正常运行,但希望避免每次使用MUI组件都手动添加该配置。

已尝试的方案

  • 在Astro Preact集成配置中设置preact({ compat: true })
  • 在package.json中通过dependencies和overrides将react、react-dom替换为npm:@preact/compat@latest
  • 查阅Material UI官方Preact示例仓库、搜索相关issue(含Vitest相关问题),尝试修改preact/hooks配置和dev命令,均无效

原因分析

这个错误的核心是服务端渲染(SSR)阶段,Material UI依赖的ThemeContext未被正确初始化。虽然preact/compat模拟了React的Context API,但在Astro的SSR流程中,服务端无法正确注入MUI的ThemeProvider上下文,导致useContext调用时获取不到ThemeContext实例,最终抛出错误。

而client:only="preact"让组件跳过SSR,仅在客户端渲染,此时客户端的Context已被正常初始化,因此不会触发错误。

可行解决办法

1. 全局包裹ThemeProvider并强制客户端初始化

在Astro根布局中用Preact组件全局包裹应用,确保ThemeContext在客户端提前激活:

  1. 创建Preact主题包装组件src/components/ThemeWrapper.tsx:
import { ThemeProvider, createTheme } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';

// 可根据需求自定义主题
const defaultTheme = createTheme();

export default function ThemeWrapper({ children }) {
  return (
    <ThemeProvider theme={defaultTheme}>
      <CssBaseline />
      {children}
    </ThemeProvider>
  );
}
  1. 在根布局文件(如src/layouts/Layout.astro)中使用该组件,并添加client:load指令:
---
import ThemeWrapper from '../components/ThemeWrapper';
---
<html lang="en">
  <body>
    <ThemeWrapper client:load>
      <slot />
    </ThemeWrapper>
  </body>
</html>

该方案让ThemeContext在客户端初始化完成,部分MUI组件可能可以正常进行SSR渲染,但仍存在部分组件依赖客户端Context的情况,需测试验证。

2. 封装MUI组件统一添加客户端渲染指令

创建封装组件,自动为MUI组件添加client:only="preact",避免重复手动配置:

以Typography为例,创建src/components/MuiTypography.astro:

---
import Typography from '@mui/material/Typography';
---
<Typography client:only="preact" {...Astro.props} />

之后在项目中直接导入这个封装组件使用即可:

---
import MuiTypography from '../components/MuiTypography.astro';
---
<MuiTypography variant="h1">Hello Material UI</MuiTypography>

同理可封装其他MUI组件,统一管理客户端渲染指令。

3. 关于版本兼容性的说明

目前Material UI v5对Preact的兼容主要集中在客户端场景,SSR下preact/compat与MUI的Context系统存在适配局限,属于MUI v5与Preact SSR的硬性兼容问题。官方提到MUI v6会更好地支持Preact,但在v6正式发布前,SSR场景下无法完全规避客户端渲染指令的使用。

建议确保使用最新版本的Astro Preact集成和preact/compat,新版本可能修复了部分兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 12:20:38