React.js + Next.js · Module 3. Forms and Effects · Lesson 3 · Point 3
React Form as a Component
In Point 2, one component displayed the form and processed its data.
Now we will divide the work between two components:
OrderFormdisplays the fields and collects their values.Appdecides what to do with the submitted values.
We will use normal named function declarations. We will not use arrow functions for our function implementations, and we will not destructure props.
All examples continue the Pizza Palace online-ordering project.
REACT · 01
1. Why Put a Form in Its Own Component?
A React component should have one clear job.
For our Pizza Palace application:
OrderFormcollects the customer's information.Appprocesses the order.
The parent may later save the order, send it to an API, show a confirmation, or update state. The form does not need to know those details.
App (parent)
│
│ gives a function to OrderForm
▼
OrderForm (child)
│
│ collects the customer's name
│ calls the function from App
▼
App receives the name
│
▼
App decides what happens next
This separation makes the form easier to read, reuse, and test.
REACT · 02
2. Remember How Props Work
Props let a parent component give information to a child component.
<Greeting name="Nikita" />
The child receives a props object:
interface GreetingProps {
name: string;
}
export default function Greeting(props: GreetingProps) {
return <h2>Hello, {props.name}!</h2>;
}
Browser Result
props.name.Read this line from left to right:
export default function Greeting(props: GreetingProps)
Greetingis the component.propsis the object it receives.GreetingPropsdescribes that object for TypeScript.
We use props.name. We do not destructure props in this lesson.
REACT · 03
3. Pass a Function Through Props
Props can also contain a function.
First, the parent creates a normal named function:
function handleOrder(customerName: string) {
console.log("Order received from:", customerName);
}
Then the parent passes that function to the child:
<OrderForm onSubmit={handleOrder} />
Here:
OrderFormis the child component.onSubmitis our custom prop name.handleOrderis the function value.
We write onSubmit={handleOrder} without parentheses because we are passing the function. We do not want to run it yet.
Later, the child runs it:
props.onSubmit(customerName);
A function passed through props and called later is often called a callback prop.
REACT · 04
4. Describe the Function Prop with TypeScript
TypeScript needs to know what the child expects to receive:
interface OrderFormProps {
onSubmit: (customerName: string) => void;
}
Read the function type like this:
onSubmit must be a function
↓
it receives one string called customerName
↓
it does not need to return a value
The => above is part of a TypeScript type. It only describes the function prop. It does not create an arrow function.
Our real function still uses a normal declaration:
function handleOrder(customerName: string) {
console.log(customerName);
}
This function matches the type because it receives one string and returns no useful value.
REACT · 05
5. Create the OrderForm Child Component
Project Structure
src/
├── components/
│ └── OrderForm.tsx
├── App.tsx
└── main.tsx
File: src/components/OrderForm.tsx
interface OrderFormProps {
onSubmit: (customerName: string) => void;
}
export default function OrderForm(props: OrderFormProps) {
function handleSubmit(formData: FormData) {
const customerName = formData.get("customerName");
if (typeof customerName !== "string") {
return;
}
props.onSubmit(customerName);
}
return (
<form action={handleSubmit}>
<label htmlFor="customerName">Customer name</label>
<input id="customerName" name="customerName" required />
<button type="submit">Place order</button>
</form>
);
}
Browser Result
OrderForm displays the field and collects its value.Follow the Important Lines
props: OrderFormProps means that the component receives the props described by the interface.
action={handleSubmit} tells React to run the form action after submission.
formData.get("customerName") reads the named input.
The typeof check confirms that the value is text.
props.onSubmit(customerName) sends that text to the function provided by the parent.
REACT · 06
6. Create the Parent App Component
File: src/App.tsx
import OrderForm from "./components/OrderForm";
export default function App() {
function handleOrder(customerName: string) {
console.log("Order received from:", customerName);
}
return (
<main>
<h1>Place your pizza order</h1>
<OrderForm onSubmit={handleOrder} />
</main>
);
}
Browser Result
Follow the Connection
The parent creates handleOrder.
function handleOrder(customerName: string) {
The parent gives it to the child.
<OrderForm onSubmit={handleOrder} />
The child calls it after collecting the name.
props.onSubmit(customerName);
REACT · 07
7. Follow the Complete Data Flow
Imagine that the customer enters Nikita:
1. App creates handleOrder
↓
2. App passes handleOrder to OrderForm
↓
3. OrderForm receives it as props.onSubmit
↓
4. The customer enters "Nikita"
↓
5. The customer submits the form
↓
6. React calls handleSubmit(formData)
↓
7. OrderForm reads customerName
↓
8. OrderForm calls props.onSubmit("Nikita")
↓
9. App's handleOrder function runs
↓
10. Console: Order received from: Nikita
There are two directions:
Function: parent → child
Data: child → parent, when the child calls the function
This pattern is often called lifting data up.
REACT · 08
8. Function Reference or Function Call?
These ideas are different.
Function Reference
handleOrder
This means the function itself. It does not run the function.
<OrderForm onSubmit={handleOrder} />
The parent passes a function reference to the child.
Function Call
handleOrder("Nikita");
The parentheses run the function.
Inside the child, this line calls the parent's function:
props.onSubmit(customerName);
Remember:
handleOrder = pass or refer to the function
handleOrder("Nikita") = run the function now
REACT · 09
9. Give Each Component One Job
The child form should collect the values. The parent should decide how to use them.
| Part | Job |
|---|---|
OrderForm |
Display fields and collect values |
App |
Process the submitted information |
onSubmit prop |
Connect the child to the parent's function |
OrderForm does not know whether the parent logs the name, saves an order, or sends an API request.
That is useful because the same form can work with different parent functions.
REACT · 10
10. Reuse the Same Form Component
The parent can display the same child more than once and give each copy a different function.
import OrderForm from "./components/OrderForm";
export default function App() {
function handleDeliveryOrder(customerName: string) {
console.log("Delivery order:", customerName);
}
function handlePickupOrder(customerName: string) {
console.log("Pickup order:", customerName);
}
return (
<main>
<section>
<h2>Delivery</h2>
<OrderForm onSubmit={handleDeliveryOrder} />
</section>
<section>
<h2>Pickup</h2>
<OrderForm onSubmit={handlePickupOrder} />
</section>
</main>
);
}
Browser Result
OrderForm component can call different parent functions.The form UI is reused. Only the processing function changes.
REACT · 11
11. Build a Complete Pizza Choice Form
Now the child will collect both the customer name and the pizza name.
File: src/components/PizzaOrderForm.tsx
interface PizzaOrder {
customerName: string;
pizzaName: string;
}
interface PizzaOrderFormProps {
onSubmit: (order: PizzaOrder) => void;
}
export default function PizzaOrderForm(props: PizzaOrderFormProps) {
function handleSubmit(formData: FormData) {
const customerName = formData.get("customerName");
const pizzaName = formData.get("pizzaName");
if (
typeof customerName !== "string" ||
typeof pizzaName !== "string"
) {
return;
}
const order: PizzaOrder = {
customerName: customerName,
pizzaName: pizzaName,
};
props.onSubmit(order);
}
return (
<form action={handleSubmit}>
<label htmlFor="customerName">Customer name</label>
<input id="customerName" name="customerName" required />
<label htmlFor="pizzaName">Pizza</label>
<input
id="pizzaName"
name="pizzaName"
defaultValue="Margherita"
/>
<button type="submit">Place order</button>
</form>
);
}
File: src/App.tsx
import PizzaOrderForm from "./components/PizzaOrderForm";
interface PizzaOrder {
customerName: string;
pizzaName: string;
}
export default function App() {
function handleOrder(order: PizzaOrder) {
console.log("Customer:", order.customerName);
console.log("Pizza:", order.pizzaName);
}
return (
<main>
<h1>Pizza Palace</h1>
<PizzaOrderForm onSubmit={handleOrder} />
</main>
);
}
Browser Result
We write every object property explicitly. We do not destructure the order or the props.
REACT · 12
12. Avoid Common Beginner Mistakes
Mistake 1 — Giving the Prop the Wrong Type
Incorrect:
interface OrderFormProps {
onSubmit: string;
}
Correct:
interface OrderFormProps {
onSubmit: (customerName: string) => void;
}
The prop contains a function, not text.
Mistake 2 — Calling the Function Too Early
Incorrect:
<OrderForm onSubmit={handleOrder("Nikita")} />
Correct:
<OrderForm onSubmit={handleOrder} />
Pass the function without parentheses.
Mistake 3 — Forgetting props
Incorrect:
onSubmit(customerName);
Correct:
props.onSubmit(customerName);
Mistake 4 — Confusing Two Different onSubmit Names
This is a custom component prop:
<OrderForm onSubmit={handleOrder} />
This is a native form event prop:
<form onSubmit={handleSubmit}>
Our child uses a React Form Action:
<form action={handleSubmit}>
The same word may appear in different places, so always check which element or component owns it.
REACT · 13
13. Practice One Step at a Time
- Create
OrderForm.tsxwith one named input and a submit button. - Add the
OrderFormPropsinterface. - Add a normal
handleSubmitfunction declaration. - Read
customerNamefromFormData. - Call
props.onSubmit(customerName). - Create a normal
handleOrderfunction inApp.tsx. - Pass it with
<OrderForm onSubmit={handleOrder} />. - Add a pizza field after the first version works.
Build one step, test it, and then add the next step.
REACT · 14
14. Summary — Remember the Connection
| Concept | Simple Meaning |
|---|---|
| Parent component | Displays the child and provides the processing function |
| Child component | Displays the form and collects values |
| Props | Information passed from parent to child |
| Callback prop | A function passed to the child to be called later |
props.onSubmit(value) |
The child calls the parent's function |
| Form Action | Gives submitted FormData to the child handler |
Final Code Pattern
src/components/OrderForm.tsx
interface OrderFormProps {
onSubmit: (customerName: string) => void;
}
export default function OrderForm(props: OrderFormProps) {
function handleSubmit(formData: FormData) {
const customerName = formData.get("customerName");
if (typeof customerName !== "string") {
return;
}
props.onSubmit(customerName);
}
return (
<form action={handleSubmit}>
<label htmlFor="customerName">Customer name</label>
<input id="customerName" name="customerName" required />
<button type="submit">Place order</button>
</form>
);
}
src/App.tsx
import OrderForm from "./components/OrderForm";
export default function App() {
function handleOrder(customerName: string) {
console.log("Order received from:", customerName);
}
return (
<main>
<h1>Pizza Palace</h1>
<OrderForm onSubmit={handleOrder} />
</main>
);
}
Browser Result
Parent passes function
↓
Child collects data
↓
Child calls function
↓
Parent processes data
Next lesson: Wait for the next source topic before adding more Module 3 material.