إتقان التعامل مع النماذج في React 19: الActins والـ Hooks الجديدة

كتب بواسطة idriss douiri profile picture إدريس الدويري

3 min read

التعامل مع النماذج في React 19 باستخدام الإجراءات والـ hooks
مشاركة

تأتي React 19 مع العديد من الميزات، خاصة التحسينات المتعلقة بالتعامل مع النماذج بما في ذلك الactions والـ hooks الجديدة. دعونا نلقي نظرة على كيفية استخدام هذه الميزات الجديدة.

إجراءات النماذج (Actions)

الإجراءات هي دوال يتم تشغيلها عند إرسال النموذج والتي يمكن أن تعمل على العميل أو الخادم باستخدام توجيه “use server”. يمكن تمرير هذه الدوال إلى خاصية action للنموذج أو عبر خاصية formAction للزر.

import { myAction } from "./actions"

async function logAction(formData) {
	console.log(formData.get("content"))
}
export default function App() {
  return (
    <form action={myAction}>
      <input type="text" name="content" />
      <button type="submit">submit</button>
      <button formAction={logAction}>log</button>
    </form>
  )
}

فوائد استخدام الإجراءات:

  • إرسال النماذج قبل تحميل حزمة JavaScript.
  • سهولة إدارة النماذج باستخدام الـ hooks الجديدة.

useFormStatus

توفر useFormStatus hook معلومات حول آخر عملية إرسال لنموذج الأب.

const { pending, data, method, action } = useFormStatus();

لتعمل هذه الـ hook يجب أن تكون داخل مكون فرعي داخل عنصر النموذج، وتقوم بإرجاع object الحالة مع 4 خصائص، بما في ذلك:

  • data: البيانات التي تم إرسالها مع النموذج على شكل كائن FormData.
  • pending: قيمة منطقية. إذا كانت true، فهذا يعني أن النموذج لا يزال في عملية المعالجة.

استخدام رائع لهذه الـ hook هو استخدام قيمة pending لتعطيل زر الإرسال لمنع المستخدم من إرسال النموذج عدة مرات.

import { useFormStatus } from "react-dom";
import { formAction } from "./actions";

function Submit() {
  const { pending } = useFormStatus()

  return <button disabled={pending}>{pending ? "جاري الإرسال..." : "إرسال"}</button>
}

export default function App() {
  return (
    <form action={formAction}>
      <input type="text" name="name" />
      <Submit />
    </form>
  );
}

useActionState

useActionState (سابقًا useFormState) هي hook أخرى تقوم بتحديث متغير الحالة بناءً على إرسال النموذج أو النقر على الزر.

const [state, formAction] = useActionState(fn, initialState);

تأخذ هذه الـ hook معطيين، وهما دالة يتم استدعاؤها عند إرسال النموذج، جنبًا إلى جنب مع الحالة الأولية، وتعيد مصفوفة تحتوي على قيمتين: الحالة الحالية والإجراء الذي سيستخدم في النموذج.

المعطى fn يستقبل الحالة السابقة ككائن formData، ويتم تعيين القيمة المرجعة كحالة جديدة.

إليك مثال بسيط باستخدام useActionState():

import { useActionState } from "react";

async function increment(previousState, formData) {
  return previousState + 1;
}

function StatefulForm({}) {
  const [state, formAction] = useActionState(increment, 0);
  return (
  <form>
    {state}
    <button formAction={formAction}>زيادة</button>
  </form>
  )
}

useOptimistic

تسمح لك الـ hook useOptimistic بعرض التحديثات المتفائلة في واجهة المستخدم مما يوفر تجربة مستخدم سلسة أثناء معالجة إجراء ما.

 const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);

تأخذ هذه الـ hook معطيين:

  • state: الحالة التي تريد تحديثها بطريقة متفائلة.
  • updateFn: دالة تأخذ الحالة الحالية والقيمة المتفائلة وترجع الحالة المتفائلة الجديدة.

وتُعيد مصفوفة تحتوي على قيمتين:

  • optimisticState: هذا هو متغير الحالة الذي يحتفظ بالقيمة المتفائلة.
  • addOptimistic: هي الدالة التي يتم استدعاؤها لتفعيل التحديث المتفائل. تأخذ قيمة متفائلة وتقوم بتمريرها إلى updateFn لحساب الحالة المتفائلة الجديدة.

تعد هذه الـ hook مثالية للاستخدام في تطبيقات وسائل التواصل الاجتماعي عندما ترغب في إعطاء رد فوري للمستخدم دون الانتظار لاستجابة الخادم (مثل الإعجاب بمنشور، أو إرسال رسالة…).

إليك مثال لتطبيق todo باستخدام useOptimistic:

import { useState, useOptimistic } from 'react';
import { saveTodo } from "./server";

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos, 
    (todos, newTodo) => [...todos, newTodo]
  );

  const addTodo = async (formData) => {
    addOptimisticTodo(formData.get("todo"));
    const todo = await saveTodo(formData.get("todo"))
    setTodos(todos => [...todos, todo])
  };

  return (
    <div>
      <form action={addTodo}>
        <input type="text" name="todo" />
        <button>أضف Todo</button>
      </form>
      {/* عرض الـ optimisticTodos */}
    </div>
  );
}