- form의 제출 상태를 확인할 수 있음. data에는 폼을 제출할 때 입력한 값들을 담고 있는 FormData 타입의 객체임.
import { useFormStatus } from "react-dom";
function UpdateName() {
const { pending, data } = useFormStatus();
return (
<>
<input name="name" />
<button disabled={pending}>변경</button>
{data && <p>{data.get("name")} as string</p>}
</>
);
}
export default UpdateName;
- form 데이터가 submit 중일때 submitting ... 표시하기
"use client";
import { useFormStatus } from "react-dom";
export default function MealFormSubmit() {
const { pending } = useFormStatus();
return (
<button disabled={pending}>
{pending ? "Submitting ..." : "Share Meal"}
</button>
);
}
- ImagePicker 만들기

"use client";
import { useState, useRef } from "react";
import classes from "./image-picker.module.css";
import Image from 'next/image'
export default function ImagePicker({ label, name }) {
const [pickedImage, setPickedImage] = useState();
const imageInput = useRef();
function handlePickClick() {
imageInput.current.click();
}
function handleImageChange(event) {
const file = event.target.files[0];
if (!file) {
return;
}
const fileReader = new FileReader();
fileReader.onload = () => {
setPickedImage(fileReader.result);
};
fileReader.readAsDataURL(file);
}
return (
<div className={classes.picker}>
<label htmlFor="image">{label}</label>
<div className={classes.controls}>
<div className={classes.preview}>
{!pickedImage && <p>No image picked yet.</p>}
{pickedImage && (
<Image
src={pickedImage}
alt="The image selected by the user."
fill
/>
)}
</div>
<input
className={classes.input}
type="file"
id={name}
accept="image.png, image/jpeg"
name={name}
ref={imageInput}
onChange={handleImageChange}
required
/>
<button
className={classes.button}
type="button"
onClick={handlePickClick}
>
Pick an Image
</button>
</div>
</div>
);
}
UseActionState

"use client";
import ImagePicker from "@/components/meals/image-picker";
import classes from "./page.module.css";
import { shareMeal } from "@/lib/actions";
import MealFormSubmit from "@/components/meals/meals-form-submit";
import { useActionState, useState, useEffect } from "react";
export default function ShareMealPage() {
const [state, formAction] = useActionState(shareMeal, { message: null });
const [isLoading, setIsLoading] = useState(false);
if (isLoading) {
console.log("isLoading ...");
}
useEffect(() => {
setIsLoading(true);
console.log("share::useEffect() called");
setIsLoading(false);
}, [isLoading]);
return (
<>
<header className={classes.header}>
<h1>
Share your <span className={classes.highlight}>favorite meal</span>
</h1>
<p>Or any other meal you feel needs sharing!</p>
</header>
<main className={classes.main}>
<form className={classes.form} action={formAction}>
<div className={classes.row}>
<p>
<label htmlFor="name">Your name</label>
<input type="text" id="name" name="name" required />
</p>
<p>
<label htmlFor="email">Your email</label>
<input type="email" id="email" name="email" required />
</p>
</div>
<p>
<label htmlFor="title">Title</label>
<input type="text" id="title" name="title" required />
</p>
<p>
<label htmlFor="summary">Short Summary</label>
<input type="text" id="summary" name="summary" required />
</p>
<p>
<label htmlFor="instructions">Instructions</label>
<textarea
id="instructions"
name="instructions"
rows="10"
required
></textarea>
</p>
<ImagePicker label="Your image" name="image" />
{state.message && <p>{state.message}</p>}
<p className={classes.actions}>
{}
<MealFormSubmit />
</p>
</form>
</main>
</>
);
}