vercel/next.js

Issue: Data Not Updating Properly in Next.js Server Actions

upangka opened this issue · 1 comments

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home China
  Available memory (MB): 40768
  Available CPU cores: 12
Binaries:
  Node: 20.13.1
  npm: 10.5.2
  Yarn: 1.22.22
  pnpm: 9.10.0
Relevant Packages:
  next: 15.0.3 // There is a newer version (15.1.0) available, upgrade recommended!
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.7.2
Next.js Config:
  output: N/A
 ⚠ There is a newer version (15.1.0) available, upgrade recommended! 
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue

Which example does this report relate to?

server action

What browser are you using? (if relevant)

Chrome 131.0.6778.109

How are you deploying your application? (if relevant)

next dev

Describe the Bug

I am working on a Next.js project with the following file structure:

app
│  page.tsx
├─actions
│      index.ts
├─api
│      route.ts
└─home
        data.ts
        edit-form.tsx
        page.tsx

Code Overview

You can view the project source code here: https://vscode.dev/github/hzz4j/nextjs-research.

  1. home/page.tsx
    This page retrieves a number from the server and passes it to the form:
import EditForm from './edit-form'
import { get } from './data'

export default async function Page() {
  const num = await get()
  return (
    <section className="mx-auto w-fit">
      <EditForm num={num} />
    </section>
  )
}
  1. home/edit-form.tsx
    This component renders a form that allows the user to update the number.
'use client'

import { useActionState } from 'react'
import { updateNum } from '../actions'

type State = {
  msg: string
}

export default function EditForm({ num }: { num: number }) {
  const initialState: State = { msg: 'success' }
  const updateNumByIndex = updateNum.bind(this, 0)
  const [state, formAction] = useActionState(updateNumByIndex, initialState)

  return (
    <form action={formAction}>
      <input type="number" name="amount" defaultValue={num} className="border p-2" />
      <p>Message: {state.msg}</p>
      <button className="rounded-md bg-green-500 p-2 text-white">Update</button>
    </form>
  )
}
  1. home/data.ts
    This module handles fetching and updating the number. The data is stored in a nums array.
'use server'

const nums = [1]

export async function get() {
  console.log('Fetching:', nums)
  return nums[0]
}

export async function update(index: number, value: number) {
  nums[index] = value
  console.log('Updated:', nums)
}
  1. actions/index.ts
    This server action updates the number and revalidates the page.
'use server'

import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { update } from '../home/data'

type State = {
  msg: string
}

export async function updateNum(index: number, _: State, formData: FormData) {
  await update(index, +formData.get('amount'))
  revalidatePath('/')
  redirect('/')
  return { msg: 'success' }
}
  1. app/page.tsx
    This is the main page, which also fetches the number:
import { get } from './home/data'

export default async function App() {
  const num = await get()
  return (
    <section className="container mx-auto text-3xl font-bold">{num}</section>
  )
}
  1. api/route.ts

This API endpoint allows updating the number via query parameters.

import { NextRequest } from 'next/server'
import { update } from '../home/data'

export async function GET(request: NextRequest) {
  const v = request.nextUrl.searchParams.get('v')
  if (v) {
    await update(0, +v)
    return new Response('success')
  }
  return new Response('error')
}

Problem Description

  1. When I update the number using the form in edit-form.tsx, e.g., changing it to 10, the page redirects back to /, but the updated value is not reflected. The nums array does not appear to be updated.

enter image description here

  1. However, when I update the number using the API endpoint (http://localhost:3000/api?v=10), the value updates successfully, and the updated value is displayed when I visit (http://localhost:3000).

enter image description here

Question

Why does updating the value via the form not work, while updating it via the API endpoint works as expected? How can I ensure that the form updates the data properly and reflects the updated value on the page after redirection?

Additional Notes

  1. I am using the use server directive for both actions/index.ts and home/data.ts.
  2. The nums array is defined as a server-side constant in data.ts.
  3. I do not want to use MySQL, Redis, or any other third-party storage solutions to store the data. I just want to understand why the Server Action is not updating the data successfully.

Any insights or suggestions would be greatly appreciated!

Expected Behavior

My expectation is that after clicking the update button in edit-form, the data will be successfully updated via Server Actions and the updated data will be displayed on the homepage /.

state40

To Reproduce

actions/index.ts
This server action updates the number and revalidates the page.

'use server'

import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { update } from '../home/data'

type State = {
  msg: string
}

export async function updateNum(index: number, _: State, formData: FormData) {
  await update(index, +formData.get('amount'))
  revalidatePath('/')
  redirect('/')
  return { msg: 'success' }
}

When I update the number using the form in edit-form.tsx, e.g., changing it to 10, the page redirects back to /, but the updated value is not reflected. The nums array does not appear to be updated. Here is the demo link

enter image description here