Next.js Server Actions & useActionState: State Management Issues (Post-Save Edit, Errors on Cancel):
Answered
ddev posted this in #help-forum
ddevOP
Hey everyone 👋,
Need some help with state management using Next.js Server Actions and useActionState for a profile edit form.
I have a client component with conditional Edit/Save/Cancel buttons. Facing a few tricky issues:
⭐ Post-Save "Edit" Flicker: After a successful save, clicking the "Edit" button immediately switches back to view mode until page refresh.
⭐Input Values Reset on Error: If validation fails (action returns errors), input fields revert to their initial defaultValue instead of keeping the user's input.
⭐Errors Persist on Cancel: After a failed save (errors visible), clicking "Cancel" exits edit mode and resets values (to defaultValue), but the validation error messages remain on screen.
Any insights on managing state (isEditing, input values, formState) in these scenarios would be awesome! Happy to share code snippets if needed.
I attached the code
Thanks!
Need some help with state management using Next.js Server Actions and useActionState for a profile edit form.
I have a client component with conditional Edit/Save/Cancel buttons. Facing a few tricky issues:
⭐ Post-Save "Edit" Flicker: After a successful save, clicking the "Edit" button immediately switches back to view mode until page refresh.
⭐Input Values Reset on Error: If validation fails (action returns errors), input fields revert to their initial defaultValue instead of keeping the user's input.
⭐Errors Persist on Cancel: After a failed save (errors visible), clicking "Cancel" exits edit mode and resets values (to defaultValue), but the validation error messages remain on screen.
Any insights on managing state (isEditing, input values, formState) in these scenarios would be awesome! Happy to share code snippets if needed.
I attached the code
Thanks!
Answered by ddev
Solution:
Problem 1:
Return a timestamp from a server action and catch it in useEffect that trigger after every successful save, preventing the UI from getting stuck in edit mode on subsequent updates
Thanks @TsukiKage for idea
Problem 2:
Using controled inputs instead of uncontrolled.
Problem 3:
Adding one more check for rendering an error message.
Problem 1:
Return a timestamp from a server action and catch it in useEffect that trigger after every successful save, preventing the UI from getting stuck in edit mode on subsequent updates
return {
message: "Profile updated successfully!",
status: Statuses.SUCCESS,
errors: {},
timestamp: Date.now(),
};
useEffect(() => {
if (formState.status === Statuses.SUCCESS) {
setIsEditing(false);
}
}, [formState.status, formState.timestamp, setIsEditing]);
Thanks @TsukiKage for idea
Problem 2:
Using controled inputs instead of uncontrolled.
const [nameValue, setNameValue] = useState(name ?? "");
const [phoneValue, setPhoneValue] = useState(phoneNumber ?? "");
useEffect(() => {
if (isEditing) {
setNameValue(name ?? "");
setPhoneValue(phoneNumber ?? "");
}
}, [isEditing, name, phoneNumber]);
Problem 3:
Adding one more check for rendering an error message.
{isEditing &&
formState.status === Statuses.ERROR &&
formState.errors?.phoneNumber && (
<p className="text-red-500 text-sm">
{Array.isArray(formState.errors.phoneNumber)
? formState.errors.phoneNumber.join(", ")
: formState.errors.phoneNumber}
</p>
)}
13 Replies
Please update your project. It maybe can help you to resolve first issue.
If it is working correctly, I will continue resolving second and third issue.
😀
@TsukiKage Please update your project. It maybe can help you to resolve first issue.
ddevOP
Give me a sec, i will try to do it 👍
Sure
@TsukiKage Sure
ddevOP
The suggested useEffect fix helped partially and resolves the issue after the first successful save.
However, a problem still occurs in a specific scenario:
If a user successfully updates their profile data once, then immediately clicks "Edit" again, makes more changes, and successfully saves a second time (all without a page refresh), the UI remains in edit mode after the second successful save completes. It doesn't exit edit mode as it did after the first save.
It seems the logic to exit the edit mode after a successful save isn't consistently reapplying or triggering correctly for subsequent successful saves within the same page session.
Any further insights on reliably managing the isEditing state based on useActionState outcomes across multiple edit/save cycles on the same page would be greatly appreciated!
However, a problem still occurs in a specific scenario:
If a user successfully updates their profile data once, then immediately clicks "Edit" again, makes more changes, and successfully saves a second time (all without a page refresh), the UI remains in edit mode after the second successful save completes. It doesn't exit edit mode as it did after the first save.
It seems the logic to exit the edit mode after a successful save isn't consistently reapplying or triggering correctly for subsequent successful saves within the same page session.
Any further insights on reliably managing the isEditing state based on useActionState outcomes across multiple edit/save cycles on the same page would be greatly appreciated!
ddevOP
Solution:
Problem 1:
Return a timestamp from a server action and catch it in useEffect that trigger after every successful save, preventing the UI from getting stuck in edit mode on subsequent updates
Thanks @TsukiKage for idea
Problem 2:
Using controled inputs instead of uncontrolled.
Problem 3:
Adding one more check for rendering an error message.
Problem 1:
Return a timestamp from a server action and catch it in useEffect that trigger after every successful save, preventing the UI from getting stuck in edit mode on subsequent updates
return {
message: "Profile updated successfully!",
status: Statuses.SUCCESS,
errors: {},
timestamp: Date.now(),
};
useEffect(() => {
if (formState.status === Statuses.SUCCESS) {
setIsEditing(false);
}
}, [formState.status, formState.timestamp, setIsEditing]);
Thanks @TsukiKage for idea
Problem 2:
Using controled inputs instead of uncontrolled.
const [nameValue, setNameValue] = useState(name ?? "");
const [phoneValue, setPhoneValue] = useState(phoneNumber ?? "");
useEffect(() => {
if (isEditing) {
setNameValue(name ?? "");
setPhoneValue(phoneNumber ?? "");
}
}, [isEditing, name, phoneNumber]);
Problem 3:
Adding one more check for rendering an error message.
{isEditing &&
formState.status === Statuses.ERROR &&
formState.errors?.phoneNumber && (
<p className="text-red-500 text-sm">
{Array.isArray(formState.errors.phoneNumber)
? formState.errors.phoneNumber.join(", ")
: formState.errors.phoneNumber}
</p>
)}
Answer