I'm still trying to understand this scenario. Can anyone suggest what is the correct way to do this in Next.js 13?
I display a list of users in a server component, for example like this (using MongoDB):
// UsersList.jsx const UsersList = () => { const users = await usersCollection.getUsers() return ( <div> {users.map(user) => <div>{user}</div>} </div> ) }
On the same page I also defined the client component for adding users:
// UsersEdit.jsx 'use client' const UsersEdit = () => { const handleAdd() => // calls POST to /api/users return // render input + button }
Both are displayed together in the server component page, as shown below:
// page.jsx const Users = () => { return ( <div> <UsersList /> <UsersEdit /> </div> ) }
How should I "reload" or "notify" UsersList
that a new user has been added to the collection to force it to show new/updated users?
P粉9044059412023-10-27 13:25:50
https://stackoverflow.com/a/75127011/17964403 This is great for mutating on the client side, but if you want to do something like searching/filtering using input from the client, and want to re-fetch the same data, you can do something like
const [searchterm, setSearchterm] = useState(""); const handleSearch = (e) => { e.preventDefault(); if(!searchterm)return router.push(/home?search=`${searchterm}`) }
In the server component you will receive the search parameter as a prop, see if the search parameter exists, if it exists then pass that parameter in the fetch call and you will get the filtered items.
P粉3453027532023-10-27 12:33:01
To reflect data updated by the client component on the server component, you can use router.refresh()
, where router
is useRouter()
. Here's an example of using a to-do list app:
// app/page.tsx
import Todo from "./todo";
async function getTodos() {
const res = await fetch("https://api.example.com/todos", { cache: 'no-store' });
const todos = await res.json();
return todos;
}
export default async function Page() {
const todos = await getTodos();
return (
<ul>
{todos.map((todo) => (
<Todo key={todo.id} {...todo} />
))}
</ul>
);
}
// app/todo.tsx "use client"; import { useRouter } from 'next/navigation'; import { useState, useTransition } from 'react'; export default function Todo(todo) { const router = useRouter(); const [isPending, startTransition] = useTransition(); const [isFetching, setIsFetching] = useState(false); // Create inline loading UI const isMutating = isFetching || isPending; async function handleChange() { setIsFetching(true); // Mutate external data source await fetch(`https://api.example.com/todo/${todo.id}`, { method: 'PUT', body: JSON.stringify({ completed: !todo.completed }), }); setIsFetching(false); startTransition(() => { // Refresh the current route and fetch new data from the server without // losing client-side browser or React state. router.refresh(); }); } return ( <li style={{ opacity: !isMutating ? 1 : 0.7 }}> <input type="checkbox" checked={todo.completed} onChange={handleChange} disabled={isPending} /> {todo.title} </li> ); }
⚠️: The crawl request is cached. That's why cache: 'no-store'
in this example.