From 3ab9db29d4d701f58c81b0ac3fbce2bd15a38c30 Mon Sep 17 00:00:00 2001 From: 2814109 <2814109k@gmail.com> Date: Sun, 5 May 2024 14:32:40 +0900 Subject: [PATCH] fix: update React hooks for optimistic form submission --- src/forms/Travel/index.tsx | 40 ++++++------ src/forms/UseOptimisticActionState/index.tsx | 69 ++++++++++++++++++++ src/forms/UseOptimisticState/index.tsx | 40 ++++++++++++ 3 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 src/forms/UseOptimisticActionState/index.tsx create mode 100644 src/forms/UseOptimisticState/index.tsx diff --git a/src/forms/Travel/index.tsx b/src/forms/Travel/index.tsx index e7f5d14..1edb4a7 100644 --- a/src/forms/Travel/index.tsx +++ b/src/forms/Travel/index.tsx @@ -1,4 +1,5 @@ -import { useOptimistic, useRef, useState } from "react"; +import { useActionState, useOptimistic, useRef } from "react"; +import { UseOptimisticStateForm } from "../UseOptimisticState"; const initDialogRef = (ref: HTMLDialogElement) => { ref.showModal(); @@ -13,33 +14,34 @@ const deliverTitle = async (title: string) => { }; export const TravelForm = () => { const formRef = useRef(null); - const [title, setTitle] = useState(""); - const [optimisticTitle, addOptimisticTitle] = useOptimistic( - title, + const [title, setTitle] = useOptimistic( + "", (_currentState, optimisticValue) => optimisticValue ); - - const sendTitle = async (formData: FormData) => { - const sentTitle = await deliverTitle(formData.get("title") as string); - setTitle(() => sentTitle); - }; - - const formAction = async (formData: FormData) => { - addOptimisticTitle(formData.get("title") as string); - formRef.current?.reset(); - await sendTitle(formData); - }; + const [response, submitAction, isPending] = useActionState< + string | null, + FormData + >( + async (_, formData) => { + const requestTitle = formData.get("title") as string; + setTitle(requestTitle); + await deliverTitle(requestTitle); + return requestTitle + "done"; + }, + null, + "/finished" + ); return ( <> -
- optimatic : {optimisticTitle} -
- label : {title} + + + label : {isPending ? title : response}
+ {isPending &&

Submitting...

}
diff --git a/src/forms/UseOptimisticActionState/index.tsx b/src/forms/UseOptimisticActionState/index.tsx new file mode 100644 index 0000000..6d3b1b1 --- /dev/null +++ b/src/forms/UseOptimisticActionState/index.tsx @@ -0,0 +1,69 @@ +import { useActionState, useOptimistic } from "react"; + +type ReturnResponse = { + ok: boolean; + message?: string; +}; + +type FormYourNameProps = { + name: string; +}; + +async function updateName(props: FormYourNameProps): Promise { + console.log(props); + await new Promise((resolve) => setTimeout(resolve, 1000)); + if (props.name.length < 3) { + return { + ok: false, + message: "Name is too short", + }; + } + return { + ok: true, + }; +} + +const parseFormData = (formData: FormData) => { + const name = formData.get("name") as string; + return { + name, + }; +}; + +export const UseOptimisticActionStateForm = () => { + const [name, setName] = useOptimistic("name"); + const [response, submitAction, isPending] = useActionState< + ReturnResponse | null, + FormData + >( + async (_, formData) => { + const props = parseFormData(formData); + setName(props.name); + const error = await updateName(props); + if (!error.ok) { + return error; + } + // redirect to /finished without 3rd argument + // redirect("/finished", RedirectType.push); + return null; + }, + null, + // redirect to /finished + "/finished" + ); + + return ( +
+
+

Current Name: {name}

+ + + {isPending &&

Submitting...

} + {response &&

{response.message}

} +
+
+ ); +}; diff --git a/src/forms/UseOptimisticState/index.tsx b/src/forms/UseOptimisticState/index.tsx new file mode 100644 index 0000000..317d769 --- /dev/null +++ b/src/forms/UseOptimisticState/index.tsx @@ -0,0 +1,40 @@ +import { useOptimistic, useRef, useState } from "react"; + +const deliverTitle = async (title: string) => { + await new Promise((res) => setTimeout(res, 1000)); + return title; +}; +export const UseOptimisticStateForm = () => { + const formRef = useRef(null); + + const [title, setTitle] = useState(""); + + const [optimisticTitle, addOptimisticTitle] = useOptimistic( + title, + (_currentState, optimisticValue) => optimisticValue + ); + + const sendTitle = async (formData: FormData) => { + const sentTitle = await deliverTitle(formData.get("title") as string); + setTitle(() => sentTitle); + }; + + const formAction = async (formData: FormData) => { + addOptimisticTitle(formData.get("title") as string); + formRef.current?.reset(); + await sendTitle(formData); + }; + + return ( + <> +
+ optimatic : {optimisticTitle} +
+ label : {title} +
+ + + + + ); +};