Next.js 中的客户端组件更改数据后更新服务器组件

Ond*_*čík 36 javascript mongodb node.js reactjs next.js

我仍在尝试理解这个场景。谁能建议在 Next.js 13 中执行此操作的正确方法是什么?

例如,我在服务器组件中显示用户列表,如下所示(使用 MongoDB):

// UsersList.jsx
const UsersList = () => {
  const users = await usersCollection.getUsers()

  return (
  <div>
    {users.map(user) => <div>{user}</div>}
  </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

在同一页面上,我还定义了用于添加用户的客户端组件:

// UsersEdit.jsx
'use client'
const UsersEdit = () => {
  const handleAdd() => // calls POST to /api/users
  return // render input + button
}
Run Code Online (Sandbox Code Playgroud)

两者在服务器组件页面中一起显示,如下所示:

// page.jsx
const Users = () => {
  return (
  <div>
    <UsersList />
    <UsersEdit />
  </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

我应该如何“重新加载”或“通知”UsersList新用户已添加到集合中以强制它显示新用户/更新的用户?

You*_*mar 43

更新服务器组件的唯一方法是重新加载页面。因为它以静态 HTML 的形式发送到浏览器,而没有附加任何 JavaScript 来实现交互。

\n

要在保持客户端状态的同时重新加载页面,您可以使用router.refresh(),其中router是 返回的值useRouter()。以下是使用待办事项列表应用程序的示例:

\n
\n

让我们考虑一个列表视图。在服务器组件内,您获取项目列表:

\n
\n
// app/page.tsx\n\nimport Todo from "./todo";\nasync function getTodos() {\n  const res = await fetch("https://api.example.com/todos", { cache: \'no-store\' });\n  const todos = await res.json();\n  return todos;\n}\n\nexport default async function Page() {\n  const todos = await getTodos();\n  return (\n    <ul>\n      {todos.map((todo) => (\n        <Todo key={todo.id} {...todo} />\n      ))}\n    </ul>\n  );\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

每个项目都有自己的客户端组件。这允许组件使用事件处理程序(如 onClick 或 onSubmit)来触发突变。

\n
\n
// app/todo.tsx\n\n"use client";\n\nimport { useRouter } from \'next/navigation\';\nimport { useState, useTransition } from \'react\';\n\nexport default function Todo(todo) {\n  const router = useRouter();\n  const [isPending, startTransition] = useTransition();\n  const [isFetching, setIsFetching] = useState(false);\n\n  // Create inline loading UI\n  const isMutating = isFetching || isPending;\n\n  async function handleChange() {\n    setIsFetching(true);\n    // Mutate external data source\n    await fetch(`https://api.example.com/todo/${todo.id}`, {\n      method: \'PUT\',\n      body: JSON.stringify({ completed: !todo.completed }),\n    });\n    setIsFetching(false);\n\n    startTransition(() => {\n      // Refresh the current route and fetch new data from the server without\n      // losing client-side browser or React state.\n      router.refresh();\n    });\n  }\n\n  return (\n    <li style={{ opacity: !isMutating ? 1 : 0.7 }}>\n      <input\n        type="checkbox"\n        checked={todo.completed}\n        onChange={handleChange}\n        disabled={isPending}\n      />\n      {todo.title}\n    </li>\n  );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x9a\xa0\xef\xb8\x8f:如果提取请求被缓存,refresh()可能会重新产生相同的结果。这就是这个例子的原因。cache: \'no-store\'

\n


小智 8

/sf/answers/5258890801/ 这非常适合在客户端进行变异,但如果您想使用客户端的输入执行搜索/过滤之类的操作,并且想要重新获取相同的数据,您可以做类似的事情

const [searchterm, setSearchterm] = useState("");
const handleSearch = (e) => {
   e.preventDefault();
   if(!searchterm)return
   router.push(/home?search=`${searchterm}`)
}
Run Code Online (Sandbox Code Playgroud)

在服务器组件中,您将收到搜索参数作为道具,查看搜索参数是否存在,如果存在,则在 fetch 调用中传递该参数,您将获得过滤后的项目。