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

السؤال

نشر

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

Warning: A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported, except via a Suspense-compatible library or framework.     at PropertyPage

أرجو التوضيح: في الكود الآتي:

"use client"
import React, { useEffect, useState } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { FaArrowLeft } from 'react-icons/fa';
import { fetchProperty } from "@/utils/requests";

const PropertyPage = async() => {
  const [property, setProperty] = useState(null)
  const [loading, setLoading] = useState(true)

  const { id } = useParams()

  useEffect(() => {
    const fetchPropertyData = async() => {

      if (!id) return

      try {
        const property = await fetchProperty(id)
        setProperty(property)
      } catch (error) {
        console.error('Error fetching property', error)
      } finally {
        setLoading(false)
      }

      if (property === null) {
        fetchPropertyData()
      }
    }
  }, [id, property])
  return (
    <>
      <section>
        <div className="container m-auto py-6 px-6">
          <Link
            href="/properties"
            className="text-green-500 hover:text-green-600 flex items-center"
          >
            <FaArrowLeft className="mr-2" /> Back to Properties
          </Link>
        </div>
      </section>

      <section className="bg-green-50">
        <div className="container m-auto py-10 px-6">
          <div className="grid grid-cols-1 md:grid-cols-70/30 w-full gap-6">
            <aside className="space-y-4">
              property single page
            </aside>
          </div>
        </div>
      </section>
    </>
  );
};

export default PropertyPage;

ظهرت رسالة الخطأ المذكورة ولكن عند حذف async في الدالة PropertyPage  صار الكود يعمل بدون مشكل.

سؤالي هو لماذا async فعلت الخطأ.

شكرا للتوضيح.

Recommended Posts

  • 0
نشر

الخطأ الذي يظهر سببه أن PropertyPage هو مكون React ويفترض أن يكون دالة وظيفية عادية وليست دالة async، في React، المكونات الوظيفية لا يمكن أن تكون دوال async لأنها يجب أن ترجع JSX مباشرة، وليس وعدا (Promise).

في الكود الذي كتبته، عند إضافة async إلى PropertyPage، تقوم بجعل هذه الدالة ترجع وعدا، مما يؤدي إلى أن React لا يعرف كيف يتعامل مع هذا الوعد ويعرض المكون، و لحل المشكلة، يمكنك فصل منطق الجلب (fetching) في useEffect كما فعلت، لكن تأكد من عدم استخدام async في دالة المكون الرئيسية. إليك كيف يمكنك إعادة كتابة الكود بشكل صحيح:

"use client"
import React, { useEffect, useState } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { FaArrowLeft } from 'react-icons/fa';
import { fetchProperty } from "@/utils/requests";

const PropertyPage = () => {
  const [property, setProperty] = useState(null);
  const [loading, setLoading] = useState(true);

  const { id } = useParams();

  useEffect(() => {
    const fetchPropertyData = async () => {
      if (!id) return;

      try {
        const property = await fetchProperty(id);
        setProperty(property);
      } catch (error) {
        console.error('Error fetching property', error);
      } finally {
        setLoading(false);
      }
    };

    fetchPropertyData();
  }, [id]);

  if (loading) {
    return <div>Loading...</div>;
  }

  return (
    <>
      <section>
        <div className="container m-auto py-6 px-6">
          <Link
            href="/properties"
            className="text-green-500 hover:text-green-600 flex items-center"
          >
            <FaArrowLeft className="mr-2" /> Back to Properties
          </Link>
        </div>
      </section>

      <section className="bg-green-50">
        <div className="container m-auto py-10 px-6">
          <div className="grid grid-cols-1 md:grid-cols-70/30 w-full gap-6">
            <aside className="space-y-4">
              property single page
            </aside>
          </div>
        </div>
      </section>
    </>
  );
};

export default PropertyPage;

في هذا الكود، يتم تنفيذ دالة fetchPropertyData داخل useEffect كما هو مطلوب، دون جعل المكون الرئيسي async. بهذه الطريقة، يمكنك ضمان أن المكون يرجع JSX وليس وعدا، وبالتالي تتجنب الخطأ الذي ظهر.

  • 0
نشر

بسبب إنشاء Promise داخل مكون عميل Client Component باستخدام fetchProperty داخل useEffect.

للتوضيح، مكونات العميل و SSR في Next.js، يتم تشغيل مكونات العميل (المُعلّمة بـ "use client") في المتصفح، بينما تشغيل مكونات الخادم Server Components على الخادم.

بالتالي عندما تستخدم async/await داخل مكون عميل، فأنت تحاول بشكل أساسي إيقاف تنفيذ JavaScript على الخادم أثناء انتظار اكتمال الوعد، وذلك غير ممكن لأن مكونات العميل لا يتم تنفيذها على الخادم.

أيضًا تستخدم React مفهوم "Suspense" للتعامل مع الحالات غير المتزامنة (مثل جلب البيانات).

إذن عند مواجهة React مكونًا في حالة "suspended" (أي في انتظار وعد)، فإنه ينتظر حتى يتم حل ذلك الوعد قبل عرض المكون، ولكن الطريقة التي تستخدم بها async/await في الكود لا تتكامل بشكل صحيح مع آلية Suspense في React.

وعند إزالة async، فإن fetchPropertyData تصبح دالة عادية لا تُرجع وعدًا، وبالتالي، لا يكون هناك انتظار للوعد، ويصبح تنفيذ الكود متزامنًا.

أي أنّ React لا يواجه أي مكونات في حالة "suspended"، وبالتالي لا يتم طرح أي خطأ.

لذا إما حذف async من المكون وإخبار Next.js أنك تقوم بإرجاع عناصر JSX، وترك الأمر لخطاف useEffect لتولي الأمر، كالتالي:

"use client"
import React, { useEffect, useState } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { FaArrowLeft } from 'react-icons/fa';
import { fetchProperty } from "@/utils/requests";

const PropertyPage = () => { 
  const [property, setProperty] = useState(null)
  const [loading, setLoading] = useState(true)

  const { id } = useParams()

  useEffect(() => {
    const fetchPropertyData = async () => {
      if (!id) return

      try {
        const property = await fetchProperty(id)
        setProperty(property)
      } catch (error) {
        console.error('Error fetching property', error)
      } finally {
        setLoading(false)
      }

      if (property === null) {
        fetchPropertyData()
      }
    }
    fetchPropertyData() // نقوم هنا بنداء الدالة مباشرًة
  }, [id, property])

  return (
    // باقي الكود
  );
};

export default PropertyPage;

أو نقل جلب البيانات إلى مكون خادم بإنشاء مكون خادم (بدون "use client") لجلب البيانات باستخدام fetchProperty، ثم مرر البيانات ك props إلى مكون العميل PropertyPage.

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

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

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

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   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.

  • إعلانات

  • تابعنا على



×
×
  • أضف...