Next.js: Update server component after client component modifies data
P粉832212776
P粉832212776 2023-10-26 17:59:27
0
2
825

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粉832212776
P粉832212776

reply all(2)
P粉904405941

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粉345302753

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.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template