บทความนี้ได้รับการสนับสนุนจาก SurveyJS มีโมเดลทางจิตที่นักพัฒนา React ส่วนใหญ่แบ่งปันโดยไม่เคยพูดคุยเรื่องนี้ออกมาดังๆ แบบฟอร์มนั้นควรจะเป็นส่วนประกอบเสมอ นี่หมายถึงสแต็กเช่น:
React Hook Form สำหรับรัฐในท้องถิ่น (การเรนเดอร์ซ้ำน้อยที่สุด การลงทะเบียนฟิลด์ตามหลักสรีระศาสตร์ การโต้ตอบที่จำเป็น) Zod สำหรับการตรวจสอบ (ความถูกต้องของอินพุต, การตรวจสอบขอบเขต, การแยกวิเคราะห์ประเภทที่ปลอดภัย) โต้ตอบแบบสอบถามสำหรับแบ็กเอนด์: การส่ง การลองใหม่ การแคช การซิงค์เซิร์ฟเวอร์ และอื่นๆ
และสำหรับแบบฟอร์มส่วนใหญ่ — หน้าจอเข้าสู่ระบบ หน้าการตั้งค่า โมดอล CRUD ของคุณ — สิ่งนี้ทำงานได้ดีจริงๆ แต่ละชิ้นทำงานของตัวเอง องค์ประกอบเรียบเรียงเรียบร้อย และคุณสามารถไปยังส่วนต่างๆ ของการใช้งานที่สร้างความแตกต่างให้กับผลิตภัณฑ์ของคุณได้ แต่ในบางครั้ง แบบฟอร์มจะเริ่มสะสมสิ่งต่างๆ เช่น กฎการมองเห็นที่ขึ้นอยู่กับคำตอบก่อนหน้า หรือค่าที่ได้รับซึ่งเรียงซ้อนผ่านสามฟิลด์ อาจเป็นทั้งหน้าที่ควรข้ามหรือแสดงโดยพิจารณาจากผลรวมทั้งหมด คุณจัดการเงื่อนไขแรกด้วย useWatch และสาขาแบบอินไลน์ ซึ่งถือว่าใช้ได้ แล้วอีกอย่าง. ถ้าอย่างนั้น คุณกำลังเข้าถึง superRefine เพื่อเข้ารหัสกฎข้ามฟิลด์ที่ Zod schema ของคุณไม่สามารถแสดงได้ตามปกติ จากนั้น การนำทางตามขั้นตอนจะเริ่มทำให้ตรรกะทางธุรกิจรั่วไหล เมื่อถึงจุดหนึ่ง คุณมองไปที่สิ่งที่คุณสร้างขึ้นและพบว่าแบบฟอร์มนั้นไม่ใช่ UI จริงๆ อีกต่อไป มันเป็นกระบวนการตัดสินใจมากกว่า และแผนผังส่วนประกอบเป็นเพียงที่ที่คุณจัดเก็บไว้เท่านั้น นี่คือจุดที่ฉันคิดว่าแบบจำลองทางจิตสำหรับแบบฟอร์มใน React พังทลายลง และไม่มีใครผิดเลยจริงๆ RHF + Zod Stack นั้นยอดเยี่ยมในสิ่งที่ออกแบบมาเพื่อมัน ปัญหาก็คือเรามักจะใช้มันต่อไปในจุดที่นามธรรมตรงกับปัญหา เพราะทางเลือกอื่นต้องใช้วิธีคิดที่แตกต่างออกไปเกี่ยวกับรูปแบบโดยสิ้นเชิง บทความนี้เกี่ยวกับทางเลือกนั้น เพื่อแสดงให้เห็นสิ่งนี้ เราจะสร้างแบบฟอร์มหลายขั้นตอนที่เหมือนกันทุกประการสองครั้ง:
ด้วย React Hook Form + Zod ที่เชื่อมต่อเข้ากับ React Query เพื่อการส่ง ด้วย SurveyJS ซึ่งถือว่าแบบฟอร์มเป็นข้อมูล — สคีมา JSON แบบง่าย — แทนที่จะเป็นแผนผังส่วนประกอบ
ข้อกำหนดเดียวกัน ตรรกะเงื่อนไขเดียวกัน การเรียก API เดียวกันในตอนท้าย จากนั้นเราจะจัดทำแผนที่อย่างชัดเจนว่าสิ่งใดเคลื่อนไหวและสิ่งใดยังคงอยู่ และจัดทำแนวทางที่เป็นประโยชน์ในการตัดสินใจว่าควรใช้โมเดลใดและเมื่อใด แบบฟอร์มที่เรากำลังสร้าง:
แบบฟอร์มนี้จะใช้โฟลว์ 4 ขั้นตอน: ขั้นตอนที่ 1: รายละเอียด
ชื่อ (จำเป็น) อีเมล (จำเป็น รูปแบบที่ถูกต้อง)
ขั้นตอนที่ 2: สั่งซื้อ
ราคาต่อหน่วย ปริมาณ อัตราภาษี ได้มา: ผลรวมย่อย ภาษี รวม.
ขั้นตอนที่ 3: บัญชีและคำติชม
คุณมีบัญชีแล้วหรือยัง? (ใช่/ไม่ใช่) ถ้าใช่ → ชื่อผู้ใช้ + รหัสผ่าน จำเป็นทั้งคู่ หากไม่มี → อีเมลได้รวบรวมไว้ในขั้นตอนที่ 1 แล้ว
คะแนนความพึงพอใจ (1–5) ถ้า ≥ 4 → ถามว่า “คุณชอบอะไร” ถ้า ≤ 2 → ถามว่า “เราจะปรับปรุงอะไรได้บ้าง”
ขั้นตอนที่ 4: ทบทวน
ปรากฏเฉพาะเมื่อผลรวม >= 100 การส่งครั้งสุดท้าย
นี่ไม่ใช่เรื่องสุดโต่ง แต่ก็เพียงพอที่จะเปิดเผยความแตกต่างทางสถาปัตยกรรม ส่วนที่ 1: การขับเคลื่อนด้วยคอมโพเนนต์ (React Hook Form + Zod) การติดตั้ง npm ติดตั้ง react-hook-form zod @hookform/resolvers @tanstack/react-query
ซอด สคีมา เริ่มจาก Zod schema กันก่อน เพราะโดยปกติแล้วจะเป็นจุดที่รูปร่างของแบบฟอร์มถูกสร้างขึ้น สำหรับสองขั้นตอนแรก — รายละเอียดส่วนบุคคลและการป้อนคำสั่งซื้อ — ทุกอย่างตรงไปตรงมา: สตริงที่ต้องระบุ ตัวเลขที่มีค่าต่ำสุด และแจงนับ ส่วนที่น่าสนใจเริ่มต้นเมื่อคุณพยายามแสดงกฎที่มีเงื่อนไข
นำเข้า { z } จาก "zod";
ส่งออก const formSchema = z.object({ firstName: z.string().min(1, "Required"), อีเมล: z.string().email("อีเมลไม่ถูกต้อง"), ราคา: z.number().min(0), ปริมาณ: z.number().min(1), TaxRate: z.number(), hasAccount: z.enum(["ใช่", "No"]), ชื่อผู้ใช้: z.string().เป็นทางเลือก() รหัสผ่าน: z.string().ตัวเลือก() ความพึงพอใจ: z.number().min(1).max(5) ค่าบวกข้อเสนอแนะ: z.string().ตัวเลือก() การปรับปรุงข้อเสนอแนะ: z.string().ตัวเลือก(),}).superRefine((ข้อมูล, ctx) => { if (data.hasAccount === "ใช่") { if (!data.username) { ctx.addIssue({ รหัส: "กำหนดเอง", เส้นทาง: ["ชื่อผู้ใช้"], ข้อความ: "จำเป็น" }); } if (!data.password || data.password.length < 6) { ctx.addIssue({ code: "custom", path: ["password"], ข้อความ: "Min 6 character" });
if (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ code: "custom", path: ["positiveFeedback"], ข้อความ: "โปรดแบ่งปันสิ่งที่คุณชอบ" }); }
if (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue({ รหัส: "กำหนดเอง", เส้นทาง:["improvementFeedback"], ข้อความ: "โปรดบอกเราว่าควรปรับปรุงอะไรบ้าง" }); }});
ประเภทการส่งออก FormData = z.infer
โปรดสังเกตว่าชื่อผู้ใช้และรหัสผ่านถูกพิมพ์เป็นตัวเลือก () แม้ว่าจะจำเป็นตามเงื่อนไขก็ตาม เนื่องจากสคีมาระดับประเภทของ Zod อธิบายรูปร่างของวัตถุ ไม่ใช่กฎที่ควบคุมเมื่อฟิลด์มีความสำคัญ ข้อกำหนดแบบมีเงื่อนไขต้องอยู่ภายใน superRefine ซึ่งทำงานหลังจากตรวจสอบรูปร่างแล้วและมีสิทธิ์เข้าถึงออบเจ็กต์ทั้งหมด การแยกจากกันนั้นไม่ใช่ข้อบกพร่อง มันเป็นเพียงสิ่งที่เครื่องมือได้รับการออกแบบมาสำหรับ: superRefine คือจุดที่ตรรกะแบบข้ามฟิลด์ดำเนินไปเมื่อไม่สามารถแสดงในโครงสร้างสคีมาได้ สิ่งที่น่าทึ่งที่นี่คือสิ่งที่สคีมานี้ไม่แสดงออก ไม่มีแนวคิดเกี่ยวกับหน้า ไม่มีแนวคิดว่าฟิลด์ใดที่มองเห็นได้ ณ จุดใด และไม่มีแนวคิดเกี่ยวกับการนำทาง ทั้งหมดนั้นจะอาศัยอยู่ที่อื่น ส่วนประกอบแบบฟอร์ม
นำเข้า { useForm, useWatch } จาก "react-hook-form"; นำเข้า { zodResolver } จาก "@hookform/resolvers/zod"; นำเข้า { useMutation } จาก "@tanstack/react-query"; นำเข้า { useState, useMemo } จาก "react"; นำเข้า { formSchema, พิมพ์ FormData } จาก "./schema";
const STEPS = ["รายละเอียด", "คำสั่งซื้อ", "บัญชี", "ตรวจสอบ"];
พิมพ์ OrderPayload = FormData & { ผลรวมย่อย: หมายเลข; ภาษี: หมายเลข; รวม: หมายเลข };
ฟังก์ชั่นการส่งออก RHFMultiStepForm() { const [ขั้นตอน, setStep] = useState (0);
การกลายพันธุ์ const = useMutation({ mututFn: async (เพย์โหลด: OrderPayload) => { const res = รอการดึงข้อมูล ("/api/orders", { วิธีการ: "โพสต์" ส่วนหัว: { "ประเภทเนื้อหา": "application/json" }, เนื้อความ: JSON.stringify (เพย์โหลด) }); ถ้า (!res.ok) โยนข้อผิดพลาดใหม่ ("ไม่สามารถส่ง"); กลับ res.json(); }, });
const { register, control, handleSubmit, formState: { error }, } = useForm
return (
);}ดูการสำรวจปากกาJS-03-RHF [แยก] โดยหกการสูญเสีย มีสิ่งต่างๆ มากมายเกิดขึ้นที่นี่ และมันก็คุ้มค่าที่จะชะลอตัวลงเพื่อดูว่าสิ่งต่างๆ จบลงที่จุดใด
ค่าที่ได้รับ — ผลรวมย่อย, ภาษี, ผลรวม — จะถูกคำนวณในส่วนประกอบผ่าน useWatch และ useMemo เนื่องจากค่าเหล่านี้ขึ้นอยู่กับค่าฟิลด์สด และไม่มีที่อื่นตามธรรมชาติสำหรับค่าเหล่านี้ กฎการมองเห็นสำหรับชื่อผู้ใช้ รหัสผ่าน PositiveFeedback และ ImprovementFeedback ใช้งานอยู่ใน JSX ในรูปแบบเงื่อนไขแบบอินไลน์ ตรรกะการข้ามขั้นตอน — หน้าตรวจสอบจะปรากฏเฉพาะเมื่อผลรวม >= 100 เท่านั้น — ถูกฝังลงในตัวแปร showSubmit และเงื่อนไขการเรนเดอร์ในขั้นตอนที่ 3 การนำทางนั้นเป็นเพียงตัวนับ useState ที่เรากำลังเพิ่มขึ้นด้วยตนเอง React Query จัดการการลองใหม่ การแคช และการทำให้ใช้งานไม่ได้ แบบฟอร์มเพียงเรียกmutate.mutateพร้อมข้อมูลที่ได้รับการตรวจสอบแล้ว
เรื่องนี้ไม่มีอะไรผิดเลย นี่ยังคงเป็น React แบบสำนวน และส่วนประกอบก็มีประสิทธิภาพค่อนข้างมาก ต้องขอบคุณวิธีที่ RHF แยกการเรนเดอร์ซ้ำ แต่ถ้าคุณต้องมอบสิ่งนี้ให้กับคนที่ไม่ได้เขียนมันและขอให้พวกเขาอธิบายภายใต้เงื่อนไขที่หน้าตรวจสอบปรากฏขึ้น พวกเขาจะต้องติดตามผ่าน showSubmit เงื่อนไขการเรนเดอร์ขั้นตอนที่ 3 และตรรกะของปุ่มนำทาง — สามที่แยกจากกัน — เพื่อสร้างกฎใหม่ที่สามารถระบุได้ในบรรทัดเดียว ใช่ แบบฟอร์มใช้งานได้ แต่พฤติกรรมนั้นไม่สามารถตรวจสอบได้ในฐานะระบบจริงๆ มันจะต้องดำเนินการทางจิต ที่สำคัญกว่านั้น การเปลี่ยนแปลงต้องอาศัยความร่วมมือทางวิศวกรรม แม้แต่การปรับแต่งเล็กๆ น้อยๆ เช่น การปรับเปลี่ยนเมื่อขั้นตอนการตรวจสอบปรากฏขึ้น ยังหมายถึงการแก้ไขส่วนประกอบ การอัปเดตการตรวจสอบ การเปิดคำขอดึง รอการตรวจสอบ และปรับใช้อีกครั้ง ส่วนที่ 2: Schema-Driven (SurveyJS) ตอนนี้เรามาสร้างโฟลว์เดียวกันโดยใช้สคีมากันดีกว่า การติดตั้ง npm ติดตั้ง Survey-core Survey-react-ui @tanstack/react-query
Survey-coreรันไทม์เอ็นจิ้นที่ไม่ขึ้นกับแพลตฟอร์มที่ได้รับใบอนุญาตจาก MIT ซึ่งขับเคลื่อนการเรนเดอร์แบบฟอร์มของ SurveyJS ซึ่งเป็นส่วนที่เราใส่ใจในที่นี้ ใช้สคีมา JSON สร้างโมเดลภายในจากโมเดลดังกล่าว และจัดการทุกอย่างที่อาจอยู่ในองค์ประกอบ React ของคุณ: การประเมินนิพจน์การมองเห็น การคำนวณค่าที่ได้รับ การจัดการสถานะเพจ การติดตามการตรวจสอบ และตัดสินใจว่า "สมบูรณ์" หมายถึงอะไรเมื่อพิจารณาว่าเพจใดที่แสดงจริง
Survey-react-uiเลเยอร์ UI / การเรนเดอร์ที่เชื่อมต่อโมเดลนั้นกับ React โดยพื้นฐานแล้วคือองค์ประกอบ
เมื่อรวมกันแล้ว จะทำให้คุณมีรันไทม์แบบฟอร์มหลายเพจที่ทำงานได้อย่างสมบูรณ์ โดยไม่ต้องเขียนโฟลว์ควบคุมแม้แต่บรรทัดเดียว ตามที่กล่าวไว้ก่อนหน้านี้ รูปแบบสคีมาเป็นเพียง JSON — ไม่มี DSL หรือกรรมสิทธิ์ใดๆ คุณสามารถอินไลน์ นำเข้าจากไฟล์ ดึงข้อมูลจาก API หรือจัดเก็บไว้ในคอลัมน์ฐานข้อมูลและไฮเดรตในขณะรันไทม์ แบบฟอร์มเดียวกันกับข้อมูล นี่คือรูปแบบเดียวกัน คราวนี้แสดงเป็นวัตถุ JSON สคีมากำหนดทุกอย่าง: โครงสร้าง การตรวจสอบ กฎการมองเห็น การคำนวณที่ได้รับ การนำทางหน้า และส่งต่อให้กับโมเดลที่ประเมิน ณ รันไทม์ นี่คือสิ่งที่ดูเหมือนเต็ม:
ส่งออก const SurveySchema = { title: "Order Flow", showProgressBar: "top", หน้า: [ { name: "details", องค์ประกอบ: [ { type: "text", name: "firstName", isRequired: true }, { type: "text", name: "email", inputType: "email", isRequired: true, validators: [{ type: "email", text: "Invalid email" }] } ] }, { ชื่อ: "คำสั่งซื้อ" องค์ประกอบ: [ { ประเภท: "ข้อความ" ชื่อ: "ราคา" ประเภทอินพุต: "หมายเลข" ค่าดีฟอลต์: 0 } { ประเภท: "ข้อความ" ชื่อ: "ปริมาณ" ประเภทอินพุต: "หมายเลข" ค่าดีฟอลต์: 1 } { ประเภท: "ดรอปดาวน์"ชื่อ: "taxRate", defaultValue: 0.1, ตัวเลือก: [ { value: 0.05, ข้อความ: "5%" }, { value: 0.1, ข้อความ: "10%" }, { value: 0.15, text: "15%" } ] }, { type: "expression", name: "subtotal", expression: "{price} {quantity}" }, { type: "expression", ชื่อ: "tax", expression: "{subtotal} {taxRate}" }, { type: "expression", name: "total", expression: "{subtotal} + {tax}" } ] }, { name: "account", องค์ประกอบ: [ { type: "radiogroup", name: "hasAccount", ตัวเลือก: ["Yes", "No"] }, { type: "text", name: "ชื่อผู้ใช้",visibleIf: "{hasAccount} = 'Yes'", isRequired: true }, { type: "text", name: "password", inputType: "password",VisibleIf: "{hasAccount} = 'Yes'", isRequired: true, validators: [{ type: "text", minLength: 6, text: "Min 6 character" }] }, { ประเภท: "rating", ชื่อ: "ความพึงพอใจ", RateMin: 1, RateMax: 5 }, { ประเภท: "ความคิดเห็น", ชื่อ: "positiveFeedback", มองเห็นได้ถ้า: "{ความพึงพอใจ} >= 4" }, { ประเภท: "ความคิดเห็น", ชื่อ: "improvementFeedback", มองเห็นได้ถ้า: "{ความพึงพอใจ} <= 2" } ] }, { ชื่อ: "บทวิจารณ์", มองเห็นได้ถ้า: "{รวม} >= 100" องค์ประกอบ: [] } ]};
เปรียบเทียบสิ่งนี้กับเวอร์ชัน RHF สักครู่
บล็อก superRefine ที่ต้องใช้ชื่อผู้ใช้และรหัสผ่านแบบมีเงื่อนไขหายไป VisibleIf: "{hasAccount} = 'Yes'" รวมกับ isRequired: true จัดการข้อกังวลทั้งสองร่วมกันบนสนามที่คุณคาดว่าจะพบพวกเขา สาย useWatch + useMemo ที่คำนวณผลรวมย่อย ภาษี และผลรวมจะถูกแทนที่ด้วยช่องนิพจน์ 3 ช่องที่อ้างอิงถึงกันด้วยชื่อ เงื่อนไขของหน้าการตรวจสอบ ซึ่งในเวอร์ชัน RHF สามารถสร้างใหม่ได้โดยการติดตามผ่าน showSubmit ซึ่งเป็นสาขาการเรนเดอร์ขั้นตอนที่ 3 เท่านั้น และสุดท้าย ตรรกะของปุ่มนำทางเป็นคุณสมบัติที่มองเห็นได้เพียงรายการเดียวบนออบเจ็กต์เพจ
ตรรกะเดียวกันอยู่ที่นั่น เพียงแต่ว่าสคีมาทำให้มีสถานที่ที่มองเห็นได้โดยแยกจากกัน แทนที่จะกระจายไปทั่วส่วนประกอบ นอกจากนี้ โปรดทราบว่าสคีมาใช้ประเภท: 'นิพจน์' สำหรับผลรวมย่อย ภาษี และผลรวม นิพจน์เป็นแบบอ่านอย่างเดียวและใช้เพื่อแสดงค่าจากการคำนวณเป็นหลัก SurveyJS ยังรองรับประเภท: 'html' สำหรับเนื้อหาคงที่ แต่สำหรับค่าที่คำนวณได้ นิพจน์คือตัวเลือกที่เหมาะสม ตอนนี้สำหรับฝั่ง React การเรนเดอร์และการส่ง ง่ายมาก เชื่อมต่อกับ API ของคุณด้วยวิธีเดียวกัน — ผ่าน useMutation หรือการดึงข้อมูลธรรมดา:
นำเข้า { useState, useEffect, useRef } จาก "react"; นำเข้า { useMutation } จาก "@tanstack/react-query"; นำเข้า { Model } จาก "survey-core"; นำเข้า { Survey } จาก "survey-react-ui"; นำเข้า "survey-core/survey-core.css";
ฟังก์ชั่นการส่งออก SurveyForm() { const [model] = useState(() => new Model(surveySchema));
การกลายพันธุ์ const = useMutation({ mutationFn: async (ข้อมูล) => { const res = รอการดึงข้อมูล ("/api/orders", { วิธีการ: "โพสต์" ส่วนหัว: { "ประเภทเนื้อหา": "application/json" }, เนื้อความ: JSON.stringify (ข้อมูล) }); ถ้า (!res.ok) โยนข้อผิดพลาดใหม่ ("ไม่สามารถส่ง"); กลับ res.json(); }, });
constmutationRef = useRef (การกลายพันธุ์); mutationRef.current = การกลายพันธุ์; useEffect(() => { const handler = (ผู้ส่ง) => MutationRef.current.mutate(sender.data); model.onComplete.add(handler); return () => model.onComplete.remove(handler); }, [model]); // ref หลีกเลี่ยงการลงทะเบียนตัวจัดการใหม่ทุกครั้งที่เรนเดอร์ (การเปลี่ยนแปลงเอกลักษณ์ของวัตถุกลายพันธุ์)
กลับ ( <> <แบบจำลองแบบสำรวจ={model} /> {mutation.isError &&
ดู Pen SurveyJS-03-SurveyJS [แยก] โดย sixthextinction
onComplete เริ่มทำงานเมื่อผู้ใช้มาถึงจุดสิ้นสุดของหน้าที่มองเห็นล่าสุด ดังนั้นหากผลรวมไม่เคยเกิน 100 และหน้าตรวจสอบถูกข้ามไป มันยังคงทำงานได้อย่างถูกต้องเนื่องจาก SurveyJS ประเมินการมองเห็นก่อนที่จะตัดสินใจว่า “หน้าสุดท้าย” หมายถึงอะไร จากนั้น sender.data จะมีคำตอบทั้งหมดพร้อมกับค่าที่คำนวณได้ (ผลรวมย่อย ภาษี ผลรวม) เป็นฟิลด์ระดับเฟิร์สคลาส ดังนั้นเพย์โหลด API จึงเหมือนกับเวอร์ชัน RHF ที่ประกอบด้วยตนเองใน onSubmit ที่รูปแบบ MutationRef เป็นแบบเดียวกับที่คุณต้องการเข้าถึงทุกที่ที่คุณต้องการตัวจัดการเหตุการณ์ที่มีความเสถียรเหนือค่าที่เปลี่ยนแปลงในการเรนเดอร์ทุกครั้ง — ไม่มี SurveyJS เฉพาะเจาะจงใด ๆ เกี่ยวกับมัน
องค์ประกอบ React ไม่มีตรรกะทางธุรกิจอีกต่อไป ไม่มี useWatch, ไม่มี JSX แบบมีเงื่อนไข, ไม่มีตัวนับก้าว, ไม่มี useMemo chain, ไม่มี superRefine React กำลังทำสิ่งที่ทำได้ดีจริงๆ: เรนเดอร์ส่วนประกอบและเชื่อมต่อเข้ากับการเรียก API อะไรเคลื่อนออกจากปฏิกิริยา?
ความกังวล สแต็ค RHF แบบสำรวจJS การมองเห็น สาขาเจเอสเอ็กซ์ มองเห็นได้ถ้า ค่าที่ได้รับ useWatch / useMemo การแสดงออก กฎข้ามสนาม ซุปเปอร์รีไฟน์ เงื่อนไขสคีมา การนำทาง สถานะขั้นตอน เพจที่มองเห็นได้ถ้า ที่ตั้งกฎ กระจายไปตามไฟล์ รวมศูนย์ในสคีมา
สิ่งที่ยังคงอยู่ใน React คือเลย์เอาต์ สไตล์ การเดินสายการส่ง และการรวมแอป ซึ่งก็คือสิ่งที่ React ได้รับการออกแบบมาเพื่อจริงๆ ทุกสิ่งทุกอย่างถูกย้ายไปยังสคีมา และเนื่องจากสคีมาเป็นเพียงออบเจ็กต์ JSON จึงสามารถจัดเก็บไว้ในฐานข้อมูล มีเวอร์ชันแยกจากโค้ดแอปพลิเคชันของคุณ หรือแก้ไขผ่านเครื่องมือภายในโดยไม่ต้องปรับใช้ ผู้จัดการผลิตภัณฑ์ที่ต้องการเปลี่ยนเกณฑ์ที่เรียกใช้หน้าการตรวจสอบสามารถทำได้โดยไม่ต้องแตะส่วนประกอบ นั่นคือความแตกต่างในการปฏิบัติงานที่สำคัญสำหรับทีมที่พฤติกรรมของฟอร์มมีการพัฒนาบ่อยครั้งและไม่ได้ขับเคลื่อนโดยวิศวกรเสมอไป เมื่อใดจึงควรใช้แต่ละวิธี? ต่อไปนี้เป็นกฎง่ายๆ ที่เหมาะกับฉัน: ลองจินตนาการถึงการลบแบบฟอร์มทั้งหมดเลย คุณจะสูญเสียอะไร?
หากเป็นหน้าจอ คุณต้องการแบบฟอร์มที่ขับเคลื่อนด้วยส่วนประกอบ หากเป็นตรรกะทางธุรกิจ เช่น ขีดจำกัด กฎการแยก และข้อกำหนดตามเงื่อนไขที่เข้ารหัสการตัดสินใจที่แท้จริง คุณต้องการกลไกจัดการสคีมา
ในทำนองเดียวกัน หากการเปลี่ยนแปลงที่กำลังจะเกิดขึ้นของคุณส่วนใหญ่เกี่ยวกับป้ายกำกับ ฟิลด์ และเค้าโครง RHF จะให้บริการคุณอย่างดี หากเกี่ยวข้องกับเงื่อนไข ผลลัพธ์ และกฎเกณฑ์ที่ฝ่ายปฏิบัติการหรือทีมกฎหมายของคุณอาจต้องปรับเปลี่ยนในบ่ายวันอังคารโดยไม่ต้องยื่นตั๋ว โมเดลสคีมากับ SurveyJS จะเหมาะสมกว่า ทั้งสองแนวทางนี้ไม่สามารถแข่งขันกันเองได้ พวกเขาจัดการกับปัญหาประเภทต่างๆ และข้อผิดพลาดที่ควรหลีกเลี่ยงคือการจับคู่สิ่งที่เป็นนามธรรมกับน้ำหนักของตรรกะไม่ตรงกัน — ปฏิบัติต่อระบบกฎเหมือนกับส่วนประกอบเนื่องจากนั่นคือเครื่องมือที่คุ้นเคย หรือเข้าถึงกลไกนโยบายเนื่องจากแบบฟอร์มขยายเป็นสามขั้นตอนและได้รับฟิลด์ที่มีเงื่อนไข แบบฟอร์มที่เราสร้างขึ้นที่นี่ตั้งอยู่ใกล้กับขอบเขตโดยจงใจ ซับซ้อนพอที่จะเผยให้เห็นความแตกต่างแต่ไม่สุดโต่งจนการเปรียบเทียบรู้สึกว่าเป็นการควบคุม รูปแบบจริงส่วนใหญ่ที่ใช้งานเทอะทะในโค้ดเบสของคุณอาจอยู่ใกล้ขอบเขตเดียวกัน และคำถามมักจะอยู่ที่ว่ามีใครตั้งชื่อว่าจริงๆ แล้วคืออะไรหรือไม่ ใช้ React Hook Form + Zod เมื่อ:
แบบฟอร์มเน้น CRUD ลอจิกนั้นตื้นและขับเคลื่อนด้วย UI; วิศวกรเป็นเจ้าของพฤติกรรมทั้งหมด แบ็กเอนด์ยังคงเป็นแหล่งที่มาของความจริง
ใช้ SurveyJS เมื่อ:
แบบฟอร์มเข้ารหัสการตัดสินใจทางธุรกิจ กฎต่างๆ พัฒนาขึ้นโดยไม่ขึ้นอยู่กับ UI ลอจิกต้องมองเห็นได้ ตรวจสอบได้ หรือมีเวอร์ชัน ผู้ที่ไม่ใช่วิศวกรมีอิทธิพลต่อพฤติกรรม แบบฟอร์มเดียวกันจะต้องทำงานบนหลายส่วนหน้า