Next.js Discord

Discord Forum

Update data in another component for new entry in the database

Unanswered
Persian posted this in #help-forum
Open in Discord
PersianOP
I have an input field in "use client", if I now send my data and save something in the database with it, how can I then update another component that is server-side so that it gets the new data?

'use client';

import { useState } from 'react';

const InputField = () => {
  const [fieldInput, setFieldInput] = useState<any>();
  const handleClick = async () => {
    await fetch('http://localhost:3000/api/todo', {
      method: 'POST',
      body: JSON.stringify({ title: fieldInput }),
    }).then(() => {
      console.log('YEAH');
    });
  };

  return (
    <div>
      <input type="text" name="input" id="input" onChange={(e) => setFieldInput(e.target.value)} placeholder="What needs to be done?" />
      <button type="button" onClick={() => handleClick()}>
        Add
      </button>
    </div>
  );
};

export default InputField;

import { prisma } from '../../../lib/prisma';

export const POST = async (request: Request) => {
  const data = await request.json();

  await prisma.todo
    .create({
      data: {
        task: data.title,
      },
    })
    .then((result) => {
      return Response.json({ data: result });
    });

  return Response.json({ error: true });
};


import { prisma } from '../lib/prisma';

const AllTodos = async () => {
  const todos = await prisma.todo.findMany({
    orderBy: {
      id: 'desc',
    },
  });

  return (
    <div>
      {todos.map((item, index) => (
        <div key={index}>{item.task}</div>
      ))}
    </div>
  );
};

export default AllTodos;

44 Replies

You create another request with search params and render the server side component based on that search params
PersianOP
Is there perhaps also a way so that I don't have to query everything again each time? I already have the list. Only the new TODOs still need to be added
@Persian Is there perhaps also a way so that I don't have to query everything again each time? I already have the list. Only the new TODOs still need to be added
The only way to update a server-side component based off user action is to either A) have the page be dynamic a.k.a rendered at request time (this won't update the page until the user refreshes or visit again when their route cache has expired in memory afaik) or the more perfered B) use a function like revalidatePath or revalidateTag in your route handler after the data has been updated in your db to immediately invalidate the cache showing the new data after a second or two (or longer depending on the situation).
PersianOP
oh thanks i didn't know about revalidatePath and tag.

I think this is the right way, but I have not yet understood how I can then update my list when adding a new task.
import prisma from '@/lib/prisma';
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export const POST = async (request: Request) => {
  const data = await request.json();

  await prisma.tasks
    .create({
      data: {
        task: data.task,
      },
    })
    .then((result) => {
      // This can go here?
      revalidateTag('tasks');
      return NextResponse.json(JSON.stringify({ revalidated: true }));
    });

  return NextResponse.json({ success: false });
};

export const GET = async (request: NextRequest) => {
  const tag: any = request.nextUrl.searchParams.get('tasks');

  revalidateTag(tag);

  const tasks = await prisma.tasks.findMany({
    orderBy: {
      id: 'desc',
    },
  });

  return NextResponse.json({ tasks });
};
PersianOP
Unfortunately, I can't get it to work.
Is it even possible to update my list, which is server side?
I don't see where you set the tag in the first place
but I've tried unstable_cache + revalidateTag in 13.5 and it plain didn't work
you might be better of with "revalidatePath" if your list of route is not too big until the tag system stabilize a bit more
In your AllTodos I see a direct database call
so you are not using tags in the first place because you are not using either "unstable_cache" or "fetch"
so indeed "revalidatePath" on the path that renders AllTodos seems more appropriate
keep in mind that there is a 5 minute client-side cache for static pages and 30 seconds for dynamic page => you might want to do an actual page refresh (f5 or ctrl+R) and not just client-side navigation
PersianOP
I rebuilt it in a route and tried this
import prisma from '@/lib/prisma';
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export const POST = async (request: Request) => {
  const data = await request.json();

  await prisma.tasks
    .create({
      data: {
        task: data.task,
      },
    })
    .then((result) => {
      revalidateTag('posts');
      return NextResponse.json(JSON.stringify({ revalidated: true }));
    });

  return NextResponse.json({ success: false });
};

export const GET = async (request: NextRequest) => {
  const tag: any = request.nextUrl.searchParams.get('tasks');
  revalidateTag(tag);

  const tasks = await prisma.tasks.findMany({
    orderBy: {
      id: 'desc',
    },
  });

  return NextResponse.json({ revalidated: true, tasks, now: Date.now() });
};
And tried to get the data like this in my Server Component
const TodoList = async () => {
  const data = await fetch('http://localhost:3000/api/todo', {
    method: 'GET',
    next: { tags: ['tasks'] },
  }).then(async (result) => {
    return await result.json();
  });

  return (
    <div>
      <h1 className="text-3xl font-bold">Tasks</h1>
      <div>
        {data.tasks.map((task: any, index: React.Key) => (
          <div key={index}>{task.task}</div>
        ))}
      </div>
    </div>
  );
};

export default TodoList;
yeah that's a possibility, that should work, does it?
but refactoring just to use fetch so you have a tag is overkill
"revalidatePath" would be a better fit until "unstable_cache" is stabilized
more than overkill it's an antipattern to call your own API in a RSC because you may be in trouble when building the app
your API doesn't run yet in this case
so the TodoList component might not even work
@Eric Burel yeah that's a possibility, that should work, does it?
PersianOP
It’s not working
@Eric Burel so the TodoList component might not even work
PersianOP
It works. But you’re right. The api is unnecessary
@Persian It works. But you’re right. The api is unnecessary
it works in dev or when building?
PersianOP
In dev. I didn't test it in production
Ok so in prod it most probably doesn't work
when building
@Eric Burel "revalidatePath" would be a better fit until "unstable_cache" is stabilized
PersianOP
Unfortunately this does not work with revalidatePath either.
@Persian Unfortunately this does not work with revalidatePath either.
yeah you might want to rollback to 13.4
in 13.5 I found revalidatePath to be broken
@aardani thats odd, it used to work in 13.4.9
yeah I didn't dig too far but I definitely had a different behaviour in 13.5 somehow
I'll wait a few versions before retrying
Barbary Lion
I found revalidateTag workin with unstable_cache in 13.5
unfortunately as far as i know you can’t use revalidatePath with unstable_cache
so you might need to create a Tag per path
Idk if there’s a tag number limit though
This is where one gets to think using fetch calling own API is the solution
because you can then revalidate a Path
Barbary Lion
yes, i think unstable_cache needs to address this problem, where you are fetching data using a third party library. you can dig in the code to retrieve the fetch request they are sending, and use it directly but often the request is signed, i-e the headers contain a unique key and thus your fetch options will be different each time, resulting in no cache hit or memoization
currently we can bypass this problem using unstable_cache but it doesn’t offer as much control than fetch does. I hope that in the future the data cache will be more flexible but i know it is a rather technical side of web computing
PersianOP
ok thanks to all :) in a previous version i can build it