Utilizing Props in Next.js with a Form Component

Currently, I am diving into the world of Nextjs and facing a challenge in passing a variable through a form component, and then further through its server action component. (I believe this is referred to as prop drilling, and I'm exploring if there's a more elegant solution.) This variable is crucial for a database query, and I'm following a tutorial to understand it better.

As a beginner, I may make super naive mistakes, so I appreciate your understanding. My main focus right now is on accessing the value of fetchuserid for my database entry:

Here is my page.tsx where I need to pass fetchuserid through AddBalanceForm:

import { fetchUser } from "@/app/components/fetchdata";
import type { UsersDb } from "@/app/components/definitions";
import ThisUserTable from "@/app/components/thisusertable";
import AddBalanceForm from "@/app/components/addbalanceform";

export default async function Page({ params: { slug } }) {
    const fetchuserid = Number(slug); 
    const user: UsersDb = await fetchUser(fetchuserid); 
    return (
      <main>
      <ThisUserTable user={user} />
      <AddBalanceForm fetchuserid={fetchuserid}/>
      </main>
    );
}

In addbalanceform.tsx:

`use client';
import { useFormState } from "react-dom";
import { userAddBalance } from "./adddata";
import SubmitButton  from "./submit-button";
import { EMPTY_FORM_STATE } from "./utils";
import { FieldError } from "./utils";
import { useToastMessage } from "./use-toast-message";
import { useFormReset } from "./useformreset";

export default function AddBalanceForm ({ fetchuserid }: { fetchuserid: number })  {

  const [formState, action] = useFormState(
    userAddBalance, 
    EMPTY_FORM_STATE,    
  );

  const noScriptFallback = useToastMessage(formState);
  const formRef = useFormReset(formState);

  return (
    <form action={action} className="flex flex-col gap-y-2" ref={formRef}>

      <label htmlFor="amount">amount</label>
      <textarea id="amount" name="amount" className="border-2" />
      <span className="text-xs text-red-400">
      <FieldError formState={formState} name="text" />
      </span>

      <SubmitButton label="Create" loading="Creating ..." />
      <span className="font-bold">{formState.message}</span>
      {noScriptFallback}
    </form>
  );
};

Regarding the server action:

'use server';
...

Now, I am unsure of how to pass the prop to the server action. I believe it needs to be handled in this block:

export default function AddBalanceForm ({ fetchuserid }: { fetchuserid: number })  {
  const [formState, action] = useFormState(
    userAddBalance, 
    EMPTY_FORM_STATE,    
  );
....

Thank you for any guidance you can provide. Much appreciated.

Answer №1

To enhance the AddBalanceForm functionality, ensure that the fetchuserid is included as a hidden input field for submission along with the form data:

1. Altering the Form Component

AddBalanceForm.tsx

'use client';

import { useFormState } from "react-dom";
import { userAddBalance } from "./adddata";
import SubmitButton from "./submit-button";
import { EMPTY_FORM_STATE } from "./utils";
import { FieldError } from "./utils";
import { useToastMessage } from "./use-toast-message";
import { useFormReset } from "./useformreset";

interface AddBalanceFormProps {
  fetchuserid: number;
}

export default function AddBalanceForm({ fetchuserid }: AddBalanceFormProps) {
  const [formState, action] = useFormState(
    (formState: FormState, formData: FormData) => userAddBalance(formState, formData, fetchuserid), // Incorporate fetchuserid in the action
    EMPTY_FORM_STATE
  );

  const noScriptFallback = useToastMessage(formState);
  const formRef = useFormReset(formState);

  return (
    <form action={action} className="flex flex-col gap-y-2" ref={formRef}>
      <input type="hidden" name="fetchuserid" value={fetchuserid} /> {/* Hidden input for fetchuserid */}

      <label htmlFor="amount">Amount</label>
      <textarea id="amount" name="amount" className="border-2" />
      <span className="text-xs text-red-400">
        <FieldError formState={formState} name="amount" />
      </span>

      <SubmitButton label="Create" loading="Creating ..." />
      <span className="font-bold">{formState.message}</span>

      {noScriptFallback}
    </form>
  );
}

2. Enhancing the Server Action

Revise the userAddBalance function to retrieve fetchuserid from the formData if communicated through a hidden field:

adddata.ts

'use server';

import { z } from 'zod';
import { revalidatePath } from 'next/cache';
import BetterSqlite3 from 'better-sqlite3';
import { FormState, toFormState } from './utils';

let db: BetterSqlite3.Database;
db = new BetterSqlite3("./coffeev1.db");

const addBalanceSchema = z.object({
  amount: z.coerce.number().min(1).max(1000),
});

export async function userAddBalance(
  formState: FormState,
  formData: FormData
) {
  // Extract fetchuserid from formData
  const fetchuserid = Number(formData.get('fetchuserid'));

  try {
    const { amount } = addBalanceSchema.parse({
      amount: formData.get('amount')
    });
    const amountInCents = amount * 100;

    const writeuser = db.prepare(`
      UPDATE user_registry
      SET kaffeestand = ?
      WHERE id = ?
    `);

    writeuser.run(amountInCents, fetchuserid);

  } catch (error) {
    console.error('Database Error:', error);
  }

  // Revalidate the cache for the page and redirect the user.
  revalidatePath(`/users/${fetchuserid}`);

  return toFormState('SUCCESS', 'Message created');
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating an object type that includes boolean values, ensuring that at least one of them is true

To ensure both AgeDivisions and EventStyles have at least one true value, I need to create a unique type for each. These are the types: type AgeDivisions = { youth: boolean; middleSchool: boolean; highSchool: boolean; college: boolean; open: bo ...

The image placeholder is missing

This is my custom Results component: This is my custom Thumbnail component: `import React from "react"; const Thumbnail = ({ result }) => { return ( <div> <h1>Thumbnail</h1> </div> ); }; export default Thumb ...

Go to a specific component located in a different module within Angular

I have a default app.component that contains a button. When this button is clicked, I want to navigate to the login.component. Below is a snippet from my app.module.ts file: import { BrowserModule } from '@angular/platform-browser'; ...

Vercel and Firebase Realtime Database causing snapshot.val() to return null during build deployment

Creating a blog application using Next.js, Firebase Realtime Database, and Vercel for hosting has been seamless on my local machine. Even after running npm run build, everything functions perfectly. However, when deployed to Netlify in production, the snap ...

NextJS custom credit card form with recurring payments using Paypal

I have successfully implemented subscriptions in nodeJS with the following code: const createSubscription = async () => { const accessToken = await getAccessToken(); const response = await axios.post( `${PAYPAL_API}/v1/billing/subscriptions`, ...

Guide on implementing a shared layout in NextJS with Auth0 integration

After following the Next docs to configure my layouts successfully, I encountered an issue with the NextJS Auth0 SDK's withPageAuthRequired wrapper that disrupts this setup. The layout pattern I've implemented is based on the guidelines outlined ...

Following the creation of the image, the functionality of the Next.js app seems to be compromised

I encountered an issue after creating a Docker image. When I build applications without Docker using npm commands, everything seems to be working fine. Screenshots are provided below. Can anyone suggest a solution to this problem? Here is the Dockerfile ...

TypeScript: displaying parameters

variable_field = [["S",".","."],[".","#","."],[".",".","T"]]; <ng-template ngFor let-array [ngForOf]="field_array" let-x="index"> <ng-t ...

Nextjs - resolving the issue of shopping carts displaying incorrect total amounts

I am currently facing an issue with the total cart amount while building a shopping cart. The problem arises when I visit the cart page as it only displays the amount of the last item added to the cart. state = { cart: { items: [], total: 0 }, }; ad ...

Comparable to LINQ SingleOrDefault()

I frequently utilize this particular pattern in my Typescript coding: class Vegetable { constructor(public id: number, public name: string) { } } var vegetableArray = new Array<Vegetable>(); vegetableArray.push(new Vegetable(1, "Carrot")); ...

I need to import a Jest mock into several different test files - how can I accomplish this?

Currently, I am creating tests for various components that utilize Next/Image. Due to continuous errors, I made the decision to mock the module in the following manner: jest.mock( `next/image`, () => function Image({ src, alt }) { ...

AngularFire 2 dispatching email for password reset

I am looking to add a feature for resetting passwords or handling forgotten passwords using AngularFire2. It looks like the function sendPasswordResetEmail is either not available in AngularFire2 or the typings have not been updated yet. I tried accessing ...

The React Hook useEffect is reporting a missing dependency: 'Navigation'

Here is the code snippet I am using: import {useContext, useEffect, useState} from 'react'; import {useHistory} from "react-router-dom"; import {MasterContext} from "../../Context/MasterProvider"; import LoginActions from &quo ...

What is the method for developing a Typescript-connected High-Order React Component with Redux?

I am looking to develop a React Higher-Order Component that can safeguard routes within my application from unauthorized users without an access token. I aim to use this HOC to wrap a Component like so in the parent component: <Route exact path ...

Nextjs google places autocomplete not providing accurate suggestions

I'm attempting to utilize Google autocomplete to retrieve the names of mosques specifically in the United Kingdom. However, the data I am receiving is global and not limited to mosques. Here is my code: import axios from "axios"; export def ...

Steps for deploying a NextJs Project on the cPanel of a free hosting platform

Looking for some guidance on how to upload my Next.js Project onto a free hosting Cpanel. I've tried various references, but haven't had much luck so far. After executing 'next build', no build folder is being created. Any advice on how ...

Having difficulty leveraging npm modules in TypeScript

I recently switched from Babel to Typescript and am facing difficulties with importing a module from node_modules. The generated .js build does not include the code from the module I'm trying to import, specifically browser-cookies. I used yarn to in ...

When attempting to access http://localhost:3000/highLightTitle.png using Next.js, a 404 error (Not Found) was encountered in the content

Despite not having any mention of GET http://localhost:3000/highLightTitle.png in my Next.js project code, I am encountering an error related to this issue. The error can be viewed here, and specifically at line 199 in content.js which can be seen here. T ...

The collapsible Navbar in flowbite-react is consistently collapsed

I have successfully completed the installation guide provided here Next, I proceeded to copy the entire default navbar from this source The navbar template always appears collapsed on all screen sizes, as illustrated in the images below. Navbar Code &qu ...

Leverage information retrieved from getServerSideProps in the custom document of a Next.js application

Utilizing getServerSideProps to fetch information about an event raises questions. The data is acquired on the server, undergoes some form of prerendering, and then a context object is sent to _document.js. While I understand that _document.js is rendered ...