在Next.js中使用AWS Amplify时出现Cannot read properties of undefined (reading 'graphql')错误
问题
我正在开发一个使用AWS Amplify与DynamoDB表交互的Next.js应用,支持用户获取和创建待办事项,但从DynamoDB获取待办事项时遇到以下错误:
Error fetching todos: TypeError: Cannot read properties of undefined (reading 'graphql') at fetchTodos (index.js:24:32) at eval (index.js:16:7) at commitHookEffectListMount (react-dom.development.js:23184:26) at commitPassiveMountOnFiber (react-dom.development.js:24960:13) at commitPassiveMountEffects_complete (react-dom.development.js:24925:9) at commitPassiveMountEffects_begin (react-dom.development.js:24912:7) at commitPassiveMountEffects (react-dom.development.js:24900:3) at flushPassiveEffectsImpl (react-dom.development.js:27073:3) at flushPassiveEffects (react-dom.development.js:27018:14) at commitRootImpl (react-dom.development.js:26969:5) at commitRoot (react-dom.development.js:26716:5) at performSyncWorkOnRoot (react-dom.development.js:26151:3) at flushSyncCallbacks (react-dom.development.js:12042:22) at eval (react-dom.development.js:25685:13)
以下是我的index.js文件相关代码:
import { Amplify, API, graphqlOperation } from 'aws-amplify'; import awsconfig from '../src/aws-exports'; import { listTodos } from '../src/graphql/queries'; import { createTodo } from '../src/graphql/mutations'; import { useState, useEffect } from 'react'; import { useAuthenticator, Authenticator } from '@aws-amplify/ui-react'; Amplify.configure(awsconfig); function Home() { const { user, signOut } = useAuthenticator((context) => [context.user]); const [todos, setTodos] = useState([]); const [todo, setTodo] = useState(''); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (user) { fetchTodos(); } }, [user]); const fetchTodos = async () => { setLoading(true); setError(null); try { const result = await API.graphql(graphqlOperation(listTodos)); console.log('Fetched todos:', result); if (result.data && result.data.listTodos && result.data.listTodos.items) { setTodos(result.data.listTodos.items); } else { setTodos([]); } } catch (err) { console.error('Error fetching todos:', err); setError('Error fetching todos'); } finally { setLoading(false); } }; const addTodo = async () => { if (todo.trim() === '') return; try { const result = await API.graphql(graphqlOperation(createTodo, { input: { name: todo } })); console.log('Created todo:', result); if (result.data && result.data.createTodo) { setTodos([...todos, result.data.createTodo]); } setTodo(''); } catch (err) { console.error('Error creating todo:', err); setError('Error creating todo'); } }; return ( <div className="min-h-screen bg-gray-100 flex flex-col items-center py-6"> {user ? ( <> <div className="bg-blue-50 p-4 rounded-lg shadow-md mb-6 w-full max-w-md text-center"> <h1 className="text-lg font-bold mb-2">Hello {user.username}</h1> <button onClick={signOut} className="px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600" > Sign out </button> </div> <div className="bg-white shadow-md rounded-lg p-6 w-full max-w-md"> <h1 className="text-2xl font-bold mb-4">ToDo List</h1> <div className="flex mb-4"> <input type="text" value={todo} onChange={(e) => setTodo(e.target.value)} placeholder="New ToDo" className="flex-grow p-2 border border-gray-300 rounded-l-lg" /> <button onClick={addTodo} className="p-2 bg-blue-500 text-white rounded-r-lg hover:bg-blue-600" > Add ToDo </button> </div> {loading ? ( <p className="text-center">Loading...</p> ) : error ? ( <p className="text-center text-red-500">{error}</p> ) : todos.length === 0 ? ( <p className="text-center">0 available</p> ) : ( <ul className="list-disc list-inside"> {todos.map((item) => ( <li key={item.id} className="p-2 border-b border-gray-300">{item.name}</li> ))} </ul> )} </div> </> ) : ( <Authenticator /> )} </div> ); } export default Home;
我已尝试以下操作:
- 验证AWS Amplify在
_app.js中配置正确 - 确认
aws-exports.js已正确生成并导入 - 确保GraphQL查询(
listTodos)和突变(createTodo)已正确定义并导入 - 检查IAM角色权限,确保包含必要的DynamoDB操作权限
环境信息:
- Node.js版本:v14.17.0
- Next.js版本:10.2.0
- AWS Amplify版本:4.3.0
- AWS AppSync GraphQL Endpoint:通过
aws-exports.js配置
请问是什么导致了Cannot read properties of undefined (reading 'graphql')错误?我该如何正确配置AWS Amplify以与我的GraphQL API交互?
原因与解决方案
这个错误的核心是API对象未被正确初始化,导致调用API.graphql时出现undefined,结合Next.js的运行机制,具体原因和修复方案如下:
核心原因
- 重复配置冲突:你同时在
_app.js和index.js中调用Amplify.configure(awsconfig),重复配置会导致Amplify内部状态混乱,引发API模块初始化失败。 - Next.js渲染环境限制:Next.js的服务端渲染(SSR)阶段,Amplify的
API模块依赖浏览器环境API,直接在页面组件中初始化Amplify会导致模块加载不完整。
具体修复步骤
1. 统一在_app.js中配置Amplify
移除index.js中的Amplify.configure(awsconfig)代码,确保Amplify只在全局入口配置一次:
// _app.js示例代码 import '../styles/globals.css'; import { Amplify } from 'aws-amplify'; import awsconfig from '../src/aws-exports'; import { Authenticator } from '@aws-amplify/ui-react'; import '@aws-amplify/ui-react/styles.css'; Amplify.configure(awsconfig); function MyApp({ Component, pageProps }) { return ( <Authenticator> <Component {...pageProps} /> </Authenticator> ); } export default MyApp;
2. 适配Next.js的服务端渲染机制
在页面中使用API模块时,确保只在客户端环境执行:
// 修改index.js中的fetchTodos函数 const fetchTodos = async () => { // 服务端环境直接返回,避免执行浏览器专属逻辑 if (typeof window === 'undefined') return; setLoading(true); setError(null); try { const result = await API.graphql(graphqlOperation(listTodos)); console.log('Fetched todos:', result); if (result.data && result.data.listTodos && result.data.listTodos.items) { setTodos(result.data.listTodos.items); } else { setTodos([]); } } catch (err) { console.error('Error fetching todos:', err); setError('Error fetching todos'); } finally { setLoading(false); } };
3. 验证依赖兼容性
确保安装的Amplify依赖版本匹配,避免版本冲突:
# 重新安装指定版本的依赖 npm install aws-amplify@4.3.0 @aws-amplify/ui-react@1.2.12
4. 检查aws-exports.js配置
确认aws-exports.js中包含GraphQL API的必要配置项:
// aws-exports.js应包含以下核心配置 export default { aws_appsync_graphqlEndpoint: "你的AppSync端点", aws_appsync_region: "你的AWS区域", aws_appsync_authenticationType: "AMAZON_COGNITO_USER_POOLS", // 其他配置项... };
验证
- 重启Next.js开发服务器
- 打开浏览器控制台,确认无初始化错误
- 登录后尝试获取待办事项,确认功能正常
内容的提问来源于stack exchange,提问作者Shaamil the COMANDO
相关产品推荐
相关产品推荐

