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

كيفية حل مشكلة Hydration في Next.js؟

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

السؤال

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

الرجاء المساعدة في تجاوز الخطأ التالي 

Error: Hydration failed because the initial UI does not match what was rendered on the server.
See more info here: https://nextjs.org/docs/messages/react-hydration-error

الكود

'use client'
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import Description from './Description';
import { IoIosClose } from 'react-icons/io';
import { Task } from '@prisma/client';
import moment from 'moment';

interface UpdateTaskProps {
    task: Task
}

const UpdateTask = ({ task }: UpdateTaskProps) => {
    const t = useTranslations("Add Task");
    const [isMounted, setIsMounted] = useState(false)

    // Handle open/close update modal
    const [updateTaskModal, setUpdateTaskModal] = useState(false)
    const openUpdateTaskModal = () => setUpdateTaskModal(true)
    const closeUpdateTaskModal = () => setUpdateTaskModal(false)

    // handle update modal
    const [title, setTitle] = useState(task.title);
    const [description, setDescription] = useState(task.description);
    const [from, setFrom] = useState(task.from);
    const [to, setTo] = useState(task.to);
    const [status, setStatus] = useState(task.status);
    useEffect(() => {
        setIsMounted(true);
        if (task) {
            setTitle(task.title || "")
            setDescription(task.description || "")
            setFrom(task.from || null);
            setTo(task.to || null);
            setStatus(task.status || "")
        }
    }, [task]);
    if (!isMounted) return null;
    return (
        <div className="relative">

            {/* Modal */}
            {updateTaskModal ? (
                <div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50">
                    <div className="bg-white dark:bg-gray-800 rounded-lg p-6  w-11/12 md:w-3/4 shadow-xl overflow-auto max-h-[85vh]">
                        {/* {alert.type && <Toast alertText={alert.alertText} type={alert.type} />} */}
                        {/* Close Button */}
                        <button
                            onClick={closeUpdateTaskModal}
                            className="absolute top-1 right-1 bg-rubyRed p-1 rounded-full hover:bg-red-600"
                        >
                            <IoIosClose className="text-3xl text-white" />
                        </button>

                        {/* Form */}
                        <form
                            // onSubmit={AddNewTask} 
                            className="space-y-6"
                        >
                            <div>
                                <label className="block text-gray-800 dark:text-gray-300 font-medium mb-2">
                                    {t("title")}
                                </label>
                                <input
                                    type="text"
                                    name="title"
                                    className="w-full p-3 border rounded-lg dark:bg-gray-700 dark:text-white"
                                    placeholder={t("enter_task_title")}
                                    value={title}
                                    onChange={(e) => setTitle(e.target.value)}
                                />
                            </div>

                            {/* Text editor Component */}
                            <Description
                                description={description}
                                setDescription={setDescription}
                            />

                            <div>
                                <label className="block text-gray-800 dark:text-gray-300 font-medium mb-2">
                                    {t("status")}
                                </label>
                                <select
                                    name="status"
                                    className="w-full p-3 border rounded-lg dark:bg-gray-700 dark:text-white"
                                    onChange={(e) => setStatus(e.target.value)}
                                >
                                    <option value="NotStarted">{t("not_started")}</option>
                                    <option value="InProgress">{t("in_progress")}</option>
                                    <option value="Completed">{t("completed")}</option>
                                </select>
                            </div>

                            <div className="grid grid-cols-2 gap-4">
                                <div>
                                    <label className="block text-gray-800 dark:text-gray-300 font-medium mb-2">
                                        {t("from")}
                                    </label>
                                    <input
                                        type="date"
                                        name="from"
                                        className="w-full p-3 border rounded-lg dark:bg-gray-700 dark:text-white"
                                        value={from ? moment(from).format('YYYY-MM-DD') : ''}
                                        onChange={(e) => setFrom(new Date(e.target.value))}
                                    />
                                </div>

                                <div>
                                    <label className="block text-gray-800 dark:text-gray-300 font-medium mb-2">
                                        {t("to")}
                                    </label>
                                    <input
                                        type="date"
                                        name="to"
                                        className="w-full p-3 border rounded-lg dark:bg-gray-700 dark:text-white"
                                        value={to ? moment(to).format('YYYY-MM-DD') : ''}
                                        onChange={(e) => setTo(new Date(e.target.value))}
                                    />
                                </div>
                            </div>
                            <button
                                type="submit"
                                className="w-full bg-royalPurple text-white p-3 rounded-lg hover:bg-slate-700 transition"
                            >{t('update')}</button>
                        </form>
                    </div>
                </div>
            ) : (<button
                onClick={openUpdateTaskModal}
                className="px-4 py-2 text-sm font-medium text-white bg-blue-500 rounded-md shadow-md 
                hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-300 transition-all"
            >
                Update
            </button>)}
        </div>
    )
}

export default UpdateTask

شكرا لكم.

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

Recommended Posts

  • 0

يبدو لي أن هنالك المشكلة اختلافا بين ما يتم تقديمه على الخادم (Server-Side Rendering) وما يتم تقديمه على جانب العميل (Client-Side) وهذا يحدث غالبا مع القيم الأولية للحالة (state) والتواريخ لهذا فبدلا من تعيين قيم task مباشرة في useState هكذا:

const [title, setTitle] = useState(task.title);
const [description, setDescription] = useState(task.description);
const [from, setFrom] = useState(task.from);
const [to, setTo] = useState(task.to);
const [status, setStatus] = useState(task.status);

استبدلها بهاته الأسطر بحيث يتم تم تعيين قيم أولية فارغة للحالة بحيث تتوافق مع القيم الأولية بين العميل والخادم كالتالي:

const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [from, setFrom] = useState(null);
const [to, setTo] = useState(null);
const [status, setStatus] = useState('');

لهذا فالحل بسيط ابدأ بقيم فارغة ثم قم بتحديثها لاحقا من خلال الخطاف useEffect كالتالي:

useEffect(() => {
    if (task) {
        setTitle(task.title || '');
        setDescription(task.description || '');
        setFrom(task.from || null);
        setTo(task.to || null);
        setStatus(task.status || '');
    }
}, [task]);

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

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

  • 0
بتاريخ 17 ساعة قال ياسر مسكين:

يبدو لي أن هنالك المشكلة اختلافا بين ما يتم تقديمه على الخادم (Server-Side Rendering) وما يتم تقديمه على جانب العميل (Client-Side) وهذا يحدث غالبا مع القيم الأولية للحالة (state) والتواريخ لهذا فبدلا من تعيين قيم task مباشرة في useState هكذا:

const [title, setTitle] = useState(task.title);
const [description, setDescription] = useState(task.description);
const [from, setFrom] = useState(task.from);
const [to, setTo] = useState(task.to);
const [status, setStatus] = useState(task.status);

استبدلها بهاته الأسطر بحيث يتم تم تعيين قيم أولية فارغة للحالة بحيث تتوافق مع القيم الأولية بين العميل والخادم كالتالي:

const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [from, setFrom] = useState(null);
const [to, setTo] = useState(null);
const [status, setStatus] = useState('');

لهذا فالحل بسيط ابدأ بقيم فارغة ثم قم بتحديثها لاحقا من خلال الخطاف useEffect كالتالي:

useEffect(() => {
    if (task) {
        setTitle(task.title || '');
        setDescription(task.description || '');
        setFrom(task.from || null);
        setTo(task.to || null);
        setStatus(task.status || '');
    }
}, [task]);

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

شكرا لكم.

في الواقع وجدت الحل لكن بطريقة أخرى حيث قمت بفصل الform على الmodal.

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

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

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

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

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

  • إعلانات

  • تابعنا على



×
×
  • أضف...