如何创建一个简单的服务器组件,可以在NextJS 13中获取数据?

flseospp  于 2023-06-22  发布在  其他
关注(0)|答案(2)|浏览(138)

我正在学习NextJS。目前,我正在使用NextJS 13和新的应用程序目录,而不是旧的页面目录。我已经尝试了各种获取数据的方法,但我没有得到任何工作。它应该像这样简单
src/app/page.tsx:

export interface ToDo {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}

const getToDos = async (): Promise<ToDo[]> => {
  const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
  console.log(`Status: ${res.status}`); // prints 'Status: 200'
  return res.json();
}

const Home = async () => {
  const toDos = await getToDos();
  return (
    <ul>
      {toDos.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
}

export default Home;

端点返回的JSON为

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

这是输出。请注意我是如何得到200 OK状态和错误消息的:

Warning: Only plain objects can be passed to Client Components from Server Components. Classes or other objects with methods are not supported.
  <... client={{queryCache: ..., mutationCache: ..., logger: ..., defaultOptions: ..., queryDefaults: ..., mutationDefaults: ..., mountCount: ...}} children=...>
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Warning: Only plain objects can be passed to Client Components from Server Components. Classes or other objects with methods are not supported.
  {queryCache: {listeners: Set, subscribe: function, config: ..., queries: ..., queriesMap: ...}, mutationCache: ..., logger: ..., defaultOptions: ..., queryDefaults: ..., mutationDefaults: ..., mountCount: ...}
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Status: 200

-  ┌ GET / 200 in 606ms
   │
   └──── GET https://jsonplaceholder.typicode.com/todos/1 200 in 67ms (cache: HIT)

- error node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (1863:12) @ resolveModelToJSON
- error Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
  {listeners: Set, subscribe: function, config: ..., queries: ..., queriesMap: ...}
                              ^^^^^^^^
    at stringify (<anonymous>)
null
- error node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (1863:12) @ resolveModelToJSON
- error Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
  {listeners: Set, subscribe: function, config: ..., queries: ..., queriesMap: ...}
                              ^^^^^^^^
    at stringify (<anonymous>)
digest: "501055159"
null

如果我在page.tsx的开头添加“use server”,我会得到一个编译错误:

Server Actions require `experimental.serverActions` option to be enabled in your Next.js config: https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions

理想情况下,我想静态生成HTML,但现在我会感谢任何工作抓取代码。

更新

我以前尝试的一个解决方案是使用Tanstack Query。我现在已经从我的layout. tsx中删除了所有这些代码。现在我得到了一个不同的错误代码:

export default async function Home(): Promise<JSX.Element> {
  const todos = await getToDos();
  console.log(todos);
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
}

error TypeError: todos.map is not a function
u4vypkhs

u4vypkhs1#

似乎你正在尝试将一个函数从服务器组件传递到客户端组件,除非它是一个服务器动作,否则这是不可能的,因为服务器动作目前仍然是一个alpha功能,你需要通过在next.config.js文件中设置experimental.serverActions来启用它们:

module.exports = {
  experimental: {
    serverActions: true,
  },
};

下面是一个服务器端组件的示例:

import "server-only";

interface ToDo {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}

async function getToDos(): Promise<ToDo[]> {
  const res = await fetch("https://jsonplaceholder.typicode.com/todos");
  return await res.json(); // by the way, you were missing an await here
}

export default async function Home(): Promise<JSX.Element> {
  const todos = await getToDos();
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
}

我强烈建议您安装server-only包,因此如果您尝试将服务器组件导入客户端,则会抛出错误。

ql3eal8s

ql3eal8s2#

正如@FabioNettis正确指出的那样,我试图获取一个不可迭代的对象。我不小心试图从路径/todos/1而不是/todos中获取。所以抓取代码实际上是正确的,尽管不是很好。良好的错误处理会使调试更容易。

相关问题