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

在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的运行机制,具体原因和修复方案如下:

核心原因

  1. 重复配置冲突:你同时在_app.js和index.js中调用Amplify.configure(awsconfig),重复配置会导致Amplify内部状态混乱,引发API模块初始化失败。
  2. 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",
  // 其他配置项...
};

验证

  1. 重启Next.js开发服务器
  2. 打开浏览器控制台,确认无初始化错误
  3. 登录后尝试获取待办事项,确认功能正常

内容的提问来源于stack exchange,提问作者Shaamil the COMANDO

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:27:33