اذهب إلى المحتوى
  • 0

تحديث البيانات عند إستخدام useContext مع Next.js

محمود_سعداوي

السؤال

السلام عليكم.

عند إنشاء حساب جديد لابد على المستخدم إدخال كافة المعطيات (last name, first name, email, password) بحيث إدخال حقل فارغ يعني ظهور رسالة خطأ.

في الكود التالي

  const context = useContext(AppContext);
  const [first_name, setFirst_name] = useState("");
  const [last_name, setLast_name] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [loading, setLoading] = useState(false);

  if (!context) {
    throw new Error("AppContext must be used within an AppProvider");
  }
  const { alert, setAlert } = context;

  const submitFormHandler = (e: FormEvent) => {
    e.preventDefault();
    setLoading(true);
    // Validation
    if (first_name === "") {
      setAlert({ alertText: "First Name is required", type: "error" });
      setLoading(false);
      return;
    }
    if (last_name === "") {
      setAlert({ alertText: "Last Name is required", type: "error" });
      setLoading(false);
      return;
    }
    if (email === "") {
      setAlert({ alertText: "Email is required", type: "error" });
      setLoading(false);
      return;
    }
    if (password === "") {
      setAlert({ alertText: "Password is required", type: "error" });
      setLoading(false);
      return;
    }
  };
*****
return (
    <div>
      {alert.alertText && (
        <Toast alertText={alert.alertText} type={alert.type}/>
      )}
      <form onSubmit={submitFormHandler}>
        --------
      </form>
    </div>
  );

عندما تكون كافة الحقول فارغة تظهر رسالة الخطأ الأولى، ولكن بعد ملئ الحقل الأول وترك بقية الحقول فارغة لاتظهر رسالة خطأ مجددا

للتوضيح.

AppContext

"use client"
import { Alert } from "@/utils/types";
import { createContext, ReactNode, useState } from "react"

type Props = {
    children: ReactNode;
};

type AppContextType = {
    darkMode: boolean,
    toggleMode: () => void,
    alert: Alert,
    setAlert: (alert: Alert) => void,
} | null

export const AppContext = createContext<AppContextType>({
    darkMode: false,
    toggleMode: () => {},
    alert: {
        type: "",
        alertText: ""
    },
    setAlert: () => {},
})

export const AppProvider = ({ children }: Props) => {
    const [darkMode, setDarkMode] = useState(false)
    const [alert, setAlert] = useState<Alert>({ type: "", alertText: "" });

    const toggleMode = () => {
        setDarkMode(!darkMode)
    }

    return (
        <AppContext.Provider value = {{toggleMode, darkMode, alert, setAlert}}>
            <div className={`${darkMode && "dark"}`}>
                {children}
            </div>
        </AppContext.Provider>
    )
}

شكرا لكم.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

Recommended Posts

  • 0

وعليكم السلام ورحمة الله وبركاته

هل تأكدت أن الحقول عند الكتابة بها يتم وضع القيم بداخلها ؟ أعتقد أن المشكلة هنا أي انه حتي عندما يتم ملئ الحقل الأول فإنه يظل فارغا أى أن first_name يظل يساوى "" لهذا فهو يدخل في الشرط الأول دائما وبما أنه يتم وضع نفس الرسالة فإن ال context لن يعيد تصير (re-render) المكون وبالتالي لن يتم ظهور رسالة الخطأ .

حاول تغير submitFormHandler إلى التالي حيث نقوم بتفريغ رسالة الخطأ أولا :

const submitFormHandler = (e: FormEvent) => {
  e.preventDefault();
  setLoading(true);

  setAlert({ alertText: "", type: "" });

  let errorMessage = "";

  if (first_name === "") {
    errorMessage = "First Name is required";
  } else if (last_name === "") {
    errorMessage = "Last Name is required";
  } else if (email === "") {
    errorMessage = "Email is required";
  } else if (password === "") {
    errorMessage = "Password is required";
  }

  if (errorMessage) {
    setAlert({ alertText: errorMessage, type: "error" });
    setLoading(false);
    return;
  }

};

وانظر هكذا هل يتم دائما طباعة ال first name فإذا كان كذلك فالمشكلة كما وضحت لك .

إذا ظلت المشكلة حاول طباعة alert بداخل الدالة submitFormHandler وانظر هل تتغير القيم بها أم لا فمن الممكن أن تكون المشكلة في ال context حيث يقوم بتغير القيمة أول مرة فقط وتحدث مشكلة ولا يوقم بتغيرها مرة أخرى.

 

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0

وعليكم السلام ، أهلاً محمود,

المشكلة التي تواجهها تحدث بسبب أنك بعد أول مرة تظهر فيها رسالة الخطأ وتقوم بتحديث الحالة (setAlert)، عند محاولة عرض رسالة خطأ أخرى، لن يتم عرض الرسالة لأنها قد تكون نفس الرسالة السابقة، وبالتالي React قد لا يعيد عرض المكون بناءً على نفس القيم.

لتجاوز هذه المشكلة يمكنك إضافة مفتاح (key) أو تغيير الهيكل قليلًا حتى تضمن أن الحالة تحدث بشكل صحيح. يمكنك تحديث الـ setAlert بحيث تعيد تعيين الرسالة عند كل محاولة تحقق من الإدخال، أو يمكنك استخدام آلية إضافية مثل ضبط مؤقت زمني لإخفاء التنبيه بعد فترة قصيرة.

قم بتغيير submitFormHandler إلى التالي ، أيضاً قمت بإضافة مؤقت زمني لإخفاء التنبيه لتحسين تجربة المستخدم :

const submitFormHandler = (e: FormEvent) => {
  e.preventDefault();
  setLoading(true);

  setAlert({ alertText: "", type: "" });

  if (first_name === "") {
    setAlert({ alertText: "First Name is required", type: "error" });
    setLoading(false);
    setTimeout(() => setAlert({ alertText: "", type: "" }), 3000); 
    return;
  }
  else if (last_name === "") {
    setAlert({ alertText: "Last Name is required", type: "error" });
    setLoading(false);
    setTimeout(() => setAlert({ alertText: "", type: "" }), 3000);
    return;
  }
  else if (email === "") {
    setAlert({ alertText: "Email is required", type: "error" });
    setLoading(false);
    setTimeout(() => setAlert({ alertText: "", type: "" }), 3000);
    return;
  }
  else if (password === "") {
    setAlert({ alertText: "Password is required", type: "error" });
    setLoading(false);
    setTimeout(() => setAlert({ alertText: "", type: "" }), 3000);
    return;
  }

  setLoading(false);
};

بالتوفيق

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0
بتاريخ 43 دقائق مضت قال محمد عاطف17:

وعليكم السلام ورحمة الله وبركاته

هل تأكدت أن الحقول عند الكتابة بها يتم وضع القيم بداخلها ؟ أعتقد أن المشكلة هنا أي انه حتي عندما يتم ملئ الحقل الأول فإنه يظل فارغا أى أن first_name يظل يساوى "" لهذا فهو يدخل في الشرط الأول دائما وبما أنه يتم وضع نفس الرسالة فإن ال context لن يعيد تصير (re-render) المكون وبالتالي لن يتم ظهور رسالة الخطأ .

حاول تغير submitFormHandler إلى التالي حيث نقوم بتفريغ رسالة الخطأ أولا :

const submitFormHandler = (e: FormEvent) => {
  e.preventDefault();
  setLoading(true);

  setAlert({ alertText: "", type: "" });

  let errorMessage = "";

  if (first_name === "") {
    errorMessage = "First Name is required";
  } else if (last_name === "") {
    errorMessage = "Last Name is required";
  } else if (email === "") {
    errorMessage = "Email is required";
  } else if (password === "") {
    errorMessage = "Password is required";
  }

  if (errorMessage) {
    setAlert({ alertText: errorMessage, type: "error" });
    setLoading(false);
    return;
  }

};

وانظر هكذا هل يتم دائما طباعة ال first name فإذا كان كذلك فالمشكلة كما وضحت لك .

إذا ظلت المشكلة حاول طباعة alert بداخل الدالة submitFormHandler وانظر هل تتغير القيم بها أم لا فمن الممكن أن تكون المشكلة في ال context حيث يقوم بتغير القيمة أول مرة فقط وتحدث مشكلة ولا يوقم بتغيرها مرة أخرى.

 

نفس المشكل. هذا هو الكود كاملا.

e.preventDefault();
  setLoading(true);

  setAlert({ alertText: "", type: "" });

  let errorMessage = "";

  if (first_name === "") {
    errorMessage = "First Name is required";
  } else if (last_name === "") {
    errorMessage = "Last Name is required";
  } else if (email === "") {
    errorMessage = "Email is required";
  } else if (password === "") {
    errorMessage = "Password is required";
  }

  if (errorMessage) {
    setAlert({ alertText: errorMessage, type: "error" });
    setLoading(false);
    return;
  }

 

بتاريخ الآن قال محمود_سعداوي:

نفس المشكل. هذا هو الكود كاملا.

e.preventDefault();
  setLoading(true);

  setAlert({ alertText: "", type: "" });

  let errorMessage = "";

  if (first_name === "") {
    errorMessage = "First Name is required";
  } else if (last_name === "") {
    errorMessage = "Last Name is required";
  } else if (email === "") {
    errorMessage = "Email is required";
  } else if (password === "") {
    errorMessage = "Password is required";
  }

  if (errorMessage) {
    setAlert({ alertText: errorMessage, type: "error" });
    setLoading(false);
    return;
  }

 

register form

"use client";
import { useTranslations } from "next-intl";
import React, { FormEvent, useContext, useState } from "react";
import Toast from "../toast";
import { AppContext } from "@/context/AppContext";

const RegisterForm = () => {
  const t = useTranslations("Auth");
  const context = useContext(AppContext);
  const [first_name, setFirst_name] = useState("");
  const [last_name, setLast_name] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [loading, setLoading] = useState(false);

  if (!context) {
    throw new Error("AppContext must be used within an AppProvider");
  }
  const { alert, setAlert } = context;

  const submitFormHandler = (e: FormEvent) => {
    e.preventDefault();
  setLoading(true);

  setAlert({ alertText: "", type: "" });

  let errorMessage = "";

  if (first_name === "") {
    errorMessage = "First Name is required";
  } else if (last_name === "") {
    errorMessage = "Last Name is required";
  } else if (email === "") {
    errorMessage = "Email is required";
  } else if (password === "") {
    errorMessage = "Password is required";
  }

  if (errorMessage) {
    setAlert({ alertText: errorMessage, type: "error" });
    setLoading(false);
    return;
  }
  };
  return (
    <div>
      {alert.alertText && (
        <Toast alertText={alert.alertText} type={alert.type}/>
      )}
      <form onSubmit={submitFormHandler}>
        {/* First Name & Last Name Fields */}
        <div className="flex justify-between">
          <div className="w-1/2 mx-2 mb-4">
            <label className="text-white dark:text-coolGray">
              {t("first_name")}
              <span className="text-rubyRed">*</span>
            </label>
            <input
              type="text"
              name="firstName"
              value={first_name}
              onChange={(e) => setFirst_name(e.target.value)}
              className={`w-full p-2 border ${first_name === "" ? "border-rubyRed" : "border-coolGray"} dark:border-white 
                     bg-white dark:bg-slateGray text-slateGray dark:text-white 
                     rounded-lg focus:outline-none focus:border-leafGreen`}
            />
          </div>

          <div className="w-1/2 mx-2 mb-4">
            <label className="text-white dark:text-coolGray">
              {t("last_name")}
              <span className="text-rubyRed">*</span>
            </label>
            <input
              type="text"
              name="lastName"
              autoComplete="off"
              value={last_name}
              onChange={(e) => setLast_name(e.target.value)}
              className={`w-full p-2 border ${first_name === "" ? "border-rubyRed" : "border-coolGray"} dark:border-white 
                     bg-white dark:bg-slateGray text-slateGray dark:text-white 
                     rounded-lg focus:outline-none focus:border-leafGreen`}
            />
          </div>
        </div>

        {/* Email Field */}
        <div className="mb-4">
          <label className="text-white dark:text-coolGray">
            {t("email")}
            <span className="text-rubyRed">*</span>
          </label>
          <input
            type="email"
            name="email"
            autoComplete="off"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            className={`w-full p-2 border ${email === "" ? "border-rubyRed" : "border-coolGray"} dark:border-white 
                   bg-white dark:bg-slateGray text-slateGray dark:text-white 
                   rounded-lg focus:outline-none focus:border-leafGreen`}
          />
        </div>

        {/* Password Field */}
        <div className="mb-4">
          <label className="text-white dark:text-coolGray">
            {t("password")}
            <span className="text-rubyRed">*</span>
          </label>
          <input
            type="password"
            name="password"
            autoComplete="off"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            className={`w-full p-2 border ${password === "" ? "border-rubyRed" : "border-coolGray"} dark:border-white 
                   bg-white dark:bg-slateGray text-slateGray dark:text-white 
                   rounded-lg focus:outline-none focus:border-leafGreen`}
          />
        </div>
        <p className="text-rubyRed mb-4">* {t('required')}</p>
        {/* Register Button */}
        <button
          type="submit"
          className="button button-block w-full py-2 text-lg font-semibold 
                 text-white bg-leafGreen hover:bg-coralRed 
                 rounded-lg transition-all duration-300"
        >
          {t("register")}
        </button>
      </form>
    </div>
  );
};

export default RegisterForm;

 

رابط هذا التعليق
شارك على الشبكات الإجتماعية

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...