-
المساهمات
260 -
تاريخ الانضمام
-
تاريخ آخر زيارة
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو Hessen Nasser
-
الخطأ الذي تواجهه يرجع على الأرجح إلى محاولة استخدام دالة createUserWithEmailAndPassword بشكل غير صحيح. هذه الدالة هي دالة غير متزامنة وتعيد موعدًا بدلاً من كائن مستخدم (User object). يجب عليك انتظار إنشاء المستخدم ومن ثم استخدام الكائن المستخدم (User object) لإضافة المزيد من التفاصيل له والتحكم فيه. لتصحيح هذا الخطأ، قم بتغيير كود التسجيل في ملف Register.jsx على النحو التالي: const handleSubmit = async (e) => { e.preventDefault(); const displayName = e.target[0].value; const email = e.target[1].value; const password = e.target[2].value; const file = e.target[3].files[0]; try { // انتظر إنشاء المستخدم من خلال اضافة await const res = await createUserWithEmailAndPassword(auth, email, password); const storageRef = ref(storage, displayName); const uploadTask = uploadBytesResumable(storageRef, file); uploadTask.on( "state_changed", (snapshot) => {}, (error) => { setErr(true); }, () => { getDownloadURL(uploadTask.snapshot.ref).then(async (downloadURL) => { await updateProfile(res.user, { displayName, photoURL: downloadURL, }); await setDoc(doc(db, "users", res.user.uid), { uid: res.user.uid, displayName, email, photoURL: downloadURL, }); }); } ); } catch (error) { setErr(true); } }; تأكد من إضافة الكلمة الأساسية await قبل استدعاء دالة createUserWithEmailAndPassword لانتظار إنشاء المستخدم والحصول على الكائن المستخدم (User object)، وذلك لتجنب الخطأ الذي واجهته في المحاولة السابقة.
-
السبب الذي يجعل الطريقتين التي ذكرتهما لا تعمل هو أنّ دوال "array_reverse" و "array_flip" لا تقوم بتعديل المصفوفة نفسها بل تعيدان مصفوفة جديدة. لذلك، إذا كنت ترغب في دمج عمل هاتين الدالتين لتعديل المصفوفة الأصلية، يمكنك القيام بذلك عن طريق القيام بالعمليات مباشرة على المصفوفة دون حفظ النتائج في متغيرات جديدة. هناك طريقتين تمكنك من القيام بذلك: الطريقة الأولى: $friends = [ "Ahmed Gamal" => "AG", "Osama Mohamed" => "OM", "Mahmoud Gamal" => "MG", "Ahmed Samy" => "AS" ]; // عكس ترتيب العناصر في المصفوفة $friends = array_reverse($friends, true); // استبدال المفاتيح بالقيم والقيم بالمفاتيح $friends = array_flip($friends); // عرض المصفوفة بعد التغيير echo '<pre>'; print_r($friends); echo '</pre>'; الطريقة الثانية: $friends = [ "Ahmed Gamal" => "AG", "Osama Mohamed" => "OM", "Mahmoud Gamal" => "MG", "Ahmed Samy" => "AS" ]; // عكس ترتيب العناصر في المصفوفة واستبدال المفاتيح بالقيم والقيم بالمفاتيح $friends = array_flip(array_reverse($friends, true)); // عرض المصفوفة بعد التغيير echo '<pre>'; print_r($friends); echo '</pre>'; بهذه الطريقتين، سترى المصفوفة النهائية بعد تطبيق الدالتين وتغيير القيم والمفاتيح وسوف تحصل علي النتيجة المطلوبة.
- 4 اجابة
-
- 1
-
وعليكم السلام ورحمة الله وبركاته، تبدو أن الكود جيد بشكل عام، ولكن هناك بعض الأمور التي يمكن تحسينها لحل المشكلة التي واجهتها. سأقدم لك التعديلات اللازمة: المشكلة الأساسية: المشكلة الأساسية التي تجعل الملف لا يحتوي على صوت عند التشغيل هي استخدام امتداد "webm" للصوت. على الرغم من أن هذا الامتداد مدعوم بواسطة العديد من المتصفحات، فإنه قد يكون غير مدعوم بعض الشيء على متصفحك. لذلك، سنستخدم امتداد "wav" بدلاً من "webm"، حيث أن "wav" هو امتداد صوت مشهور ومدعوم جيدًا. تحسين الأمان: في ملف "audio.php"، لاحظت أنه يتم قبول الملفات بامتداد "png" أيضًا، وهذا غير ضروري لعملية التسجيل الصوتي. من الأفضل أن نقوم بتحديد امتداد "wav" فقط للملفات الصوتية. الآن، سنقوم بتعديل الكود لحل هذه المشكلة وتحسين الأمان: ملف audio.html: <!DOCTYPE html> <html> <body> <button onclick="startRecording();">تسجيل صوتي</button> <button onclick="stopRecording();">إيقاف التسجيل</button> <br> <a id="downloadLink" style="display:none;"></a> <br> <audio style="display:none" id="audioElement" controls="controls" src=""></audio> <script> let audioChunks = []; let mediaRecorder = null; let audioBlob = null; let audioUrl = null; function startRecording() { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { mediaRecorder = new MediaRecorder(stream); mediaRecorder.start(); mediaRecorder.addEventListener("dataavailable", event => { audioChunks.push(event.data); }); }); } function stopRecording() { mediaRecorder.addEventListener("stop", () => { audioBlob = new Blob(audioChunks, { type: "audio/wav" }); audioUrl = URL.createObjectURL(audioBlob); let audioElement = document.getElementById("audioElement"); audioElement.src = audioUrl; audioElement.style.display = 'block'; let downloadLink = document.getElementById("downloadLink"); downloadLink.href = audioUrl; downloadLink.download = "recording.wav"; downloadLink.innerText = 'اضغط هنا لحفظ الملف'; uploadAudio(); }); mediaRecorder.stop(); } function uploadAudio() { var formData = new FormData(); formData.append("audio", audioBlob, "recording.wav"); fetch("audio.php", { method: "POST", body: formData }) .then(response => response.json()) .then(data => { if (data.aud) { alert(data.url); } else { alert(data.error); } }) .catch(error => { console.error("حدث خطأ أثناء رفع الصوت", error); }); } </script> </body> </html> ملف audio.php: <?php function _file($file, $allowedExtension, $size, $folder) { global $load_error; $rand = array('A', 'a', 'B', 'b', 'C', 'c', 'D', 'b', 'E', 'e', 'F', 'f', 'G', 'g', 'J', 'j', 'K', 'k', 'L', 'l', 'H', 'h', 'S', 's', 'V', 'v', 'T', 't', 'Q', 'q', 'W', 'w', 'Y', 'y', 'U', 'u', 'I', 'i', 'O', 'o', 'P', 'p', 'X', 'x', 'N', 'n', 'M', 'm', 'R', 'r', 'Z', 'z'); $text = ''; for ($i = 0; $i < rand(10, 20); $i++) { $text = $text . $rand[rand(0, 51)]; } $fileName = $_FILES[$file]['name']; $fileSize = $_FILES[$file]['size']; $fileTmp = $_FILES[$file]['tmp_name']; $fileType = $_FILES[$file]['type']; $fileExtensions = end(explode('.', $fileName)); if (isset($fileName) and $fileName != '') { if (in_array($fileExtensions, $allowedExtension)) { if ($fileSize > $size) { $load_error = 2; return false; } else { //نقوم بتغيير اسم الملف وحفضه في المجلد $location = $folder . "/" . $fileName; $location_new = $folder . "/" . $text . '.' . $fileExtensions; move_uploaded_file($fileTmp, $location); rename($location, $location_new); return $location_new; } } else { $load_error = 1; return false; } } else { $load_error = 0; return false; } } if ($audio_url = _file('audio', ['wav'], 1000 * 1000 * 5, 'upload')) { $arr['aud'] = true; $arr['url'] = $audio_url; } else { $errors[] = 'لا يوجد ملف '; $errors[] = 'الملف غير مدعوم'; $errors[] = 'حجم الملف كبير'; $arr['aud'] = false; $arr['error'] = $errors[$load_error]; } echo json_encode($arr); ?> بعد التعديلات، يجب أن يتم تسجيل الصوت بامتداد "wav" ويرفع للسيرفر، وعند تشغيل الملف ستجد الصوت موجودًا ويمكن سماعه بشكل صحيح. كما قمنا بتحسين الأمان للسماح فقط بامتداد "wav" للملفات الصوتية.
-
وعليكم السلام،يمكنني مساعدتك في توفير تمارين عن الـ functions بمستويات مختلفة: مبتدئ، متوسط وصعب. سأقدم لك بعض التمارين في كل مستوى: مستوى المبتدئ: تمرين 1: قم بكتابة دالة بسيطة تستقبل اثنين من الأعداد وتقوم بجمعهما وإرجاع الناتج. تمرين 2: اكتب دالة تستقبل اسم شخص وتقوم بطباعة رسالة ترحيبية تحتوي على اسمه. مستوى المتوسط: تمرين 1: اكتب دالة تستقبل قائمة من الأرقام وتعيد قائمة جديدة تحتوي على الأعداد الزوجية فقط. تمرين 2: انشئ دالة تقوم بحساب مجموع الأرقام من 1 إلى عدد معين (مثلاً: sum_numbers(n) حيث n هو العدد)، ثم قم باستدعاء هذه الدالة واطبع الناتج. مستوى الصعوبة: تمرين 1: انشئ دالة تستقبل نص وتعيد قائمة تحتوي على تردد كل حرف في النص (عدد مرات ظهوره). مثال: إذا قمت بإدخال "hello"، يجب أن تعيد الدالة قائمة تحتوي على [('h', 1), ('e', 1), ('l', 2), ('o', 1)]. تمرين 2: اكتب دالة تستقبل رقمًا وتقوم بإرجاع True إذا كان الرقم عبارة عن عدد أولي و False إذا لم يكن. (عدد أولي هو العدد الذي يمكن قسمه على 1 ونفسه فقط). أتمنى أن تكون هذه التمارين مفيدة لك في تطوير مهاراتك في الـ functions. إذا كنت بحاجة إلى أي توضيح إضافي أو مساعدة في كتابة الحلول، فلا تتردد في طرح أسئلتك.
-
الكود الذي قدمته يبدو أنه يقوم بضغط ملف الفيديو بشكل مؤقت وإظهاره في `VideoView`، لكنه لا يتضمن تضمين الصوت في ملف الفيديو المضغوط. هذا يحدث لأن الكود يستخدم مكتبة `SiliCompressor` التي تهتم بضغط الفيديو فقط دون الصوت. إذا كنت ترغب في ضمان وجود الصوت في الفيديو المضغوط، يمكنك استخدام مكتبة أخرى تدعم ضغط الفيديو مع الصوت مثل `FFmpeg` أو `MediaCodec` في Android. هذه المكتبات توفر مزيدًا من التحكم على عملية الضغط وتتيح لك ضبط إعدادات الصوت والفيديو وتجميعها معًا. ومع ذلك، يُرجى ملاحظة أن استخدام مكتبات متطورة مثل `FFmpeg` يتطلب فهمًا أعمق للعمل مع الصوت والفيديو في Android وقد تحتاج إلى معالجة الاستثناءات والإعدادات المناسبة لضمان عملها بشكل صحيح. إذا كنت ترغب في مواصلة استخدام مكتبة `SiliCompressor` بدون صوت، فيمكنك متابعة استخدام الكود الحالي بنفس الطريقة التي قدمتها. وإذا كنت بحاجة إلى ضغط الفيديو مع الصوت، فعليك بالبحث عن مكتبات تدعم هذه الميزة واستخدامها بالطريقة المناسبة.
-
لتنفيذ بحث متعدد الأشكال في قاعدة بيانات SQL باستخدام Laravel Eloquent، يمكنك استخدام الدالة WHERE مع عبارات متعددة لكل كلمة في الاسم. يمكنك استخدام العلامة النجمية (%) كحرف وايلدكارد للبحث عن أي جزء من النص. هنا هو مثال باستخدام Laravel Eloquent للبحث عن الاسم بكل الأشكال التي ذكرتها: $searchTerm = 'محمد فادي عادل جواريش'; $results = DB::table('اسم_الجدول') ->where(function ($query) use ($searchTerm) { $keywords = explode(' ', $searchTerm); foreach ($keywords as $keyword) { $query->orWhere('اسم_الحقل', 'like', '%' . $keyword . '%'); } }) ->get(); ضع "اسم_الجدول" بدلًا من اسم الجدول الفعلي في قاعدة البيانات الخاصة بك، و"اسم_الحقل" بدلًا من اسم الحقل الذي تحتوي عليه الأسماء. هذا الاستعلام سيبحث عن جميع الأسماء التي تحتوي على أي من الكلمات الموجودة في المتغير $searchTerm. وسيعيد جميع الصفوف التي تطابق هذا الشرط. مثال: إذا كان لديك الأسماء التالية في قاعدة البيانات: محمد جواريش عادل محمد فادي سامي جواريش وأدخلت $searchTerm = 'محمد فادي عادل جواريش'، فسيقوم البحث بإعادة الأسماء رقم 1 ورقم 2 لأنها تحتوي على أي من الكلمات المذكورة في البحث. تنويه: قم بتغيير "اسم_الجدول" و"اسم_الحقل" وفقًا لاسم الجدول والحقل الفعلي في قاعدة البيانات الخاصة بك.
-
الوقت الذي يستغرقه لإنهاء دورة تطوير التطبيقات باستخدام بايثون يعتمد على عدة عوامل، بما في ذلك مدة الدورة التدريبية نفسها، والتزامك بالدراسة والممارسة، وخلفيتك السابقة في البرمجة، ومستوى تطلعاتك الشخصية. قد تتفاوت الدورات في المدة، فمنها ما يستمر لبضعة أسابيع ومنها ما يستغرق شهورًا. بالنسبة للتعلم وتجربة البرمجة، فإن الأمر يعتمد على شخصيتك وأسلوب تعلمك وتفرغك للدراسة والتطبيق. بعض الأشخاص يتعلمون بسرعة ويحافظون على المعلومات لفترة طويلة، بينما يحتاج آخرون إلى مزيد من التكرار والممارسة لتثبيت المفاهيم في ذاكرتهم. يمكن أن تحدث النسيان بشكل طبيعي إذا لم تمارس المعلومات المكتسبة بانتظام. لذا، من الأفضل القيام بمشاريع عملية وتطبيقات عملية لتحفيز الاستفادة الأمثل من المعلومات وتحسين الاحتفاظ بها. إذا كنت تشعر بأنك تخزن كميات كبيرة من المعلومات وتنساها بسرعة، فقد تكون هناك طرق لتحسين التذكر والاحتفاظ بالمعلومات: التكرار والممارسة المنتظمة: كرر المفاهيم والتدرب على استخدامها بانتظام لتعزيز التذكر. التعلم النشط: تحدث عن المفاهيم وحاول شرحها لشخص آخر، فهذا يعزز تفهمك وتذكرك للمعلومات. المشاريع العملية: قم ببناء مشاريع وتطبيقات عملية باستخدام البرمجة بالبايثون لتعزيز تطبيق المفاهيم عملياً. تقييم فهمك: حاول حل التحديات والمسائل البرمجية للتحقق من فهمك وممارستك. المراجعة المنتظمة: كرر المواد السابقة من الدورة بشكل منتظم للتأكد من استمرارية التذكر. على العموم، التعلم واكتساب المعرفة هو عملية مستمرة وطبيعية، وقد تتطلب الأمر بعض الجهد لتحسين التذكر والاحتفاظ بالمعلومات. لذا، لا تيأس واستمر في الممارسة والتعلم، وستلاحظ تحسنًا تدريجيًا في قدرتك على الاحتفاظ بالمعلومات. https://academy.hsoub.com/questions/12276-مشكل-النسيان/
-
القوائم والصفوف هما مصطلحان يتم استخدامهما في سياق مختلف، وهما غالبًا ما يُشار إليهما في عدة مجالات. دعنا نوضح الاختلافات بينهما: 1. القوائم (Lists): القوائم هي هياكل بيانات تحتوي على مجموعة من العناصر التي يتم تنظيمها في ترتيب معين. يمكن أن تكون العناصر في القوائم متنوعة، مثل أعداد صحيحة، نصوص، كائنات، إلخ. تكون القوائم غالبًا متغيرة الحجم، مما يعني أنه يمكن إضافة وحذف العناصر منها بحرية. عادةً ما يكون لكل عنصر في القائمة موضع محدد يُعرف باسم "فهرس" أو "اندكس" (index) يبدأ عادة من الصفر. القوائم تستخدم بشكل واسع في برمجة الحاسوب والعديد من التطبيقات. مثال على قائمة من الأرقام: [1, 3, 5, 7, 9] 2. الصفوف (Rows): الصفوف عادة ما تكون مرادفة للأفقية، وهي مصطلح يُستخدم بشكل أساسي في الجداول وقواعد البيانات. تُمثل الصفوف السجلات الفردية في الجدول، وتحتوي على مجموعة من البيانات المتعلقة بمدخل واحد في الجدول. وبما أن الجداول تكون ثنائية الأبعاد، فتحتوي على صفوف وأعمدة، حيث يمثل كل صف سجلًا فرديًا ويحتوي على بيانات مرتبطة بهذا السجل. مثال على جدول يحتوي على صفوف: | الاسم | العمر | المدينة | |--------|---- |----------- | | أحمد | 30 | القاهرة | | محمد | 25 | الرياض | | ليلى | 28 | دبي | لتوضيح الاختلاف، يمكن القول أن القائمة هي مجموعة من العناصر المرتبة بشكل خطي، في حين أن الصفوف تشير عادةً إلى السجلات الموجودة في جدول ثنائي الأبعاد.
- 6 اجابة
-
- 1
-
سأقدم لك دليلًا سريعًا حول كيفية تثبيت Python على نظام macOS. خطوة 1: التأكد من عدم تواجد Python مثبت بالفعل قد يكون Python مثبتًا بالفعل على نظامك، لذلك من الأفضل التحقق أولاً. افتح "Terminal" (الموجود في Applications > Utilities) واكتب الأمر التالي: python3 --version إذا كان Python مثبتًا، فسوف ترى رقم الإصدار الذي تم تثبيته. وإذا لم يكن Python مثبتًا، فلنراجع الخطوة التالية. خطوة 2: تثبيت Homebrew (اختياري) إذا كنت لا تملك Homebrew على نظامك، فإن تثبيته قد يكون مفيدًا. Homebrew هو أداة تسهل تثبيت البرامج والحزم على macOS. يمكنك العثور على معلومات حول تثبيته على الموقع الرسمي:homebrew خطوة 3: تثبيت Python بعد تثبيت Homebrew أو إذا كنت تفضل تجاوز هذه الخطوة، يمكنك تثبيت Python باستخدام الأمر التالي في "Terminal": brew install python خطوة 4: التحقق من التثبيت بعد الانتهاء من التثبيت، قم بإعادة التحقق مرة أخرى باستخدام الأمر: python3 --version إذا كان قد تم التثبيت بنجاح، فسترى رقم الإصدار الخاص بـ Python. ملاحظات إضافية: تحتوي macOS عادة على Python 2 مثبتًا مسبقًا. ومع ذلك، يُفضل استخدام Python 3 لأن Python 2 لم يعد مدعومًا بعد الآن. عند كتابة الأوامر في "Terminal"، تأكد من عدم الانقطاع عن الإنترنت أثناء التثبيت حتى لا يتعذر الوصول إلى الخوادم ويتعذر تنزيل الحزم بنجاح. إذا كانت لديك أي مشاكل أخرى، يُفضل أن تذكر رسالة الخطأ أو التفاصيل التي تواجهك بها لأتمكن من تقديم المساعدة بشكل أفضل.
- 3 اجابة
-
- 1
-
عند استخدام محتوى مثل الخطوط والأيقونات والصور التي تخضع لترخيص (license) معين، من الضروري أن تلتزم بشروط تلك الترخيص وتقوم بوضع attribution أو الإشارة إلى صاحب حقوق الملكية الفكرية (المؤلف) للمحتوى. هذا يهدف إلى إظهار الاحترام لحقوق المؤلف ومساعدتك في الامتثال للشروط التي تحكم استخدام المحتوى. تختلف شروط الترخيص من مصدر إلى آخر، لذلك من المهم أن تتحقق من تفاصيل الترخيص الخاص بكل محتوى تستخدمه. عادةً ما توفر المواقع التي توفر محتوى تحت ترخيص معين صفحة تفاصيل الترخيص أو ملفًا نصيًا (مثل ملف "LICENSE" أو "COPYING") يحتوي على شروط استخدام المحتوى. يجب قراءة هذه الشروط والتأكد من استيفاء جميع متطلبات الترخيص، بما في ذلك وضع attribution بالطريقة المناسبة. بالنسبة لمكتبة jQuery، فهي تحتوي على ترخيص MIT، الذي يتطلب وضع attribution عند استخدام المكتبة. يمكنك وضع attribution عادةً عن طريق وضع تعليق في الكود يحتوي على معلومات حول المكتبة ورابط إلى صفحة الترخيص. على سبيل المثال: <!-- jQuery from Google hosted libraries --> <!-- More info: https://developers.google.com/speed/libraries#jquery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> التعليق الذي يحمل معلومات الattribution يعتبر طريقة شائعة لوضع attribution بشكل صحيح. يمكنك أيضًا الاطلاع على تفاصيل ترخيص jQuery في صفحة المشروع الرسمية للحصول على معلومات دقيقة حول كيفية وضع attribution. في النهاية، دائمًا ما يكون الالتزام بشروط الترخيص ووضع attribution أمرًا هامًا للحفاظ على الامتثال القانوني واحترام حقوق المؤلف والمطورين.
-
يجب عليك التوجه الي قسم الدعم الخاص بالدورة التعليمية المذكوره وقم بطرح الطلب عليهم وسوف يتم التواصل معك وحل مشكلتك.
-
تفضل هذا الكود بعد حل المشكلات المذكوره سابقا تمت إضافة getFilePathFromUri() كدالة مساعدة للحصول على مسار الملف من URI المستخدمة في selectVideo(). هذا يساعد في الحصول على المسار الصحيح للملف الذي تم تحديده من قبل المستخدم. أيضًا، تم إضافة تعليقات توضيحية لأجزاء محددة من الكود. يمكنك استخدام هذا الكود كنقطة بداية لإجراء التعديلات اللازمة حسب احتياجاتك. public class UploadVideoActivity extends AppCompatActivity implements difroved.ExampleDialogeListener { TextView uploader; RoundedImageView geter; VideoView vedgetr; MediaController mc; File file; private static final int SELECT_VIDEO_REQUEST = 0; public Uri videoUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_uploadved); geter = findViewById(R.id.geter); uploader = findViewById(R.id.uploader); vedgetr = findViewById(R.id.vedgetr); mc = new MediaController(uploadved.this); vedgetr.setMediaController(mc); geter.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { selectVideo(); } }); } private void selectVideo() { Intent intent = new Intent(); intent.setType("video/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, "Select Video"), SELECT_VIDEO_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == SELECT_VIDEO_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) { videoUri = data.getData(); vedgetr.setVideoURI(videoUri); vedgetr.start(); // Get the file path from the video URI String filePath = getFilePathFromUri(videoUri); file = new File(filePath); float size1 = file.length() / 1024f; long size = file.length(); MediaPlayer mp = MediaPlayer.create(this, videoUri); // Compress the video in the background new CompressVideoTask().execute("false", videoUri.toString(), file.getPath()); int duration = mp.getDuration(); mp.release(); String durationStr = String.format("%d", TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration))); String durationStr2 = String.format("%d", TimeUnit.MILLISECONDS.toMinutes(duration)); } } // Helper method to get the file path from the URI private String getFilePathFromUri(Uri uri) { String filePath = ""; String[] projection = {MediaStore.Video.Media.DATA}; Cursor cursor = getContentResolver().query(uri, projection, null, null, null); if (cursor != null && cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA); filePath = cursor.getString(columnIndex); cursor.close(); } return filePath; } private class CompressVideoTask extends AsyncTask<String, String, String> { Dialog dialogo; @Override protected void onPreExecute() { super.onPreExecute(); dialogo = ProgressDialog.show(uploadved.this, "برجاء الانتظار", "جاري تجهيز الفيديو"); } @Override protected String doInBackground(String... strings) { String vediopath = null; // Get the video URI. Uri uritoup = Uri.parse(strings[1]); // Compress the video. try { vediopath = SiliCompressor.with(uploadved.this).compressVideo(uritoup, strings[2]); } catch (URISyntaxException e) { throw new RuntimeException(e); } return vediopath; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); dialogo.dismiss(); // Get the compressed video file. File filea = new File(s); // Get the file size in kilobytes. float size2 = filea.length() / 1024f; // Log the file size. Log.d("sizs", String.format("Size : %.2f kB", size2)); // Set the display name of the compressed video file. String displayName = String.valueOf(Calendar.getInstance().getTimeInMillis() + ".mp4"); } } }
-
يبدو أن لديك مشكلة في استرداد الرسائل الصحيحة بين المستخدم الحالي والمستخدم الآخر في تطبيق دردشة Laravel الخاص بك. هنا بعض الأمور التي يجب مراجعتها في الأكواد الخاصة بك: تحقق من دالة chats() في نموذج User: يجب أن يكون الشرط orWhere الأول يسترد الدردشات حيث يكون المستخدم الحالي هو المرسل والمستخدم الآخر هو المستلم. يجب أن يكون الشرط orWhere الثاني يسترد الدردشات حيث يكون المستخدم الحالي هو المستلم والمستخدم الآخر هو المرسل. لاحظ أنه يجب استخدام الشرط where في كل من الشرطين داخل الـ orWhere. تحقق من دالة users() في نموذج Chat: يجب أن تستخدم العلاقة belongsTo بشكل صحيح لتعيين العلاقة بين نموذج Chat و User. تحقق من دالة messages() في نموذج Chat: يجب استخدام العلاقة hasMany بشكل صحيح لتعيين العلاقة بين نموذج Chat و Message. تأكد من أن المفتاح الأجنبي لنموذج Message هو chat_id. تحقق من دالة chats() في نموذج Message: يجب استخدام العلاقة belongsTo بشكل صحيح لتعيين العلاقة بين نموذج Message و Chat. تأكد من أن المفتاح الأجنبي لنموذج Message هو chat_id. تحقق من دالة getMessages() في وحدة التحكم (Controller): تأكد من أنك تستخدم Auth::user() للحصول على المستخدم الحالي. يبدو أن الشرط $username !== $user->username غير ضروري، لأنه يعود بالفعل بالمستخدم الحالي. تأكد من أن الدردشات التي تم استردادها تتناسب مع المستخدم الحالي كمستلم والمستخدم الآخر كمرسل. بعد إجراء هذه التغييرات، يجب أن يتم استرداد الرسائل بين المستخدم الحالي والمستخدم الذي يتم الدردشة معه بشكل صحيح.
-
يبدو أن لديك بعض المشاكل في كودك. هنا بعض الأمور التي يجب أن تلاحظها: يجب عليك إغلاق الأقواس الناقصة في طريقة onCreate() الخاصة بك. يجب إضافة السطر } قبل طريقة selectVideo(). قمت بتعريف متغير file كـ File جديد، ولكن لم تقم بتعيين مسار الملف. يبدو أنه يجب تعيين مسار الملف المستهدف في هذا المتغير قبل استخدامه في طريقة Compressvedio. يجب تمرير المعلمات الصحيحة إلى طريقة Compressvedio. يجب أن يكون لديك 3 معاملات: strings[0] يحتوي على القيمة "false"، strings[1] يحتوي على سلسلة URI لمقطع الفيديو، و strings[2] يحتوي على مسار الملف الذي سيتم حفظ المقطع المضغوط فيه. تأكد من تمرير هذه المعاملات بالترتيب الصحيح في الدالة execute(). في طريقة Compressvedio.onPostExecute() ، يجب استخدام المتغير size2 للإشارة إلى الحجم بدلاً من المتغير size1. بعد أن تقوم بإصلاح هذه المشاكل المحددة، قد تستمر في وجود مشاكل أخرى. في حال حدوث أي مشكلة إضافية، يرجى تقديم معلومات إضافية حول الخطأ الذي تواجهه وأية رسائل خطأ تظهر في وحدة التحكم.
- 6 اجابة
-
- 1
-
يجب عليك ان تغير طريقة الاستيراد استخدم الاستيراد المطلق بدلاً من الاستيراد النسبي إذا لم يكن لديك حاجة واضحة للاستيراد النسبي. بدلاً من from .module import function، يمكنك استخدام from package.module import function، حيث "package" هو اسم الحزمة الرئيسية و "module" هو اسم الموديول المراد استيراده. وإذا كان لديك أي مشكلة في الدورة التدريبية، يُرجى التعليق أسفل فيديو الدورة في قسم التعليقات، حيث يمكننا مساعدتك بشكل أفضل. أما إذا كان لديك أسئلة عامة في مجال البرمجة، فيُمكنك طرحها هنا في قسم أسئلة البرمجة.
-
لحساب متطلبات الذاكرة العشوائية (RAM) المطلوبة لعملية التعدين واستهلاك الهاش لتعدين العملات الرقمية، تحتاج إلى معرفة الخوارزمية المستخدمة في التعدين والعملة الرقمية المحددة التي تنوي التعدين بها. كل خوارزمية وعملة رقمية لها متطلبات مختلفة، وبالتالي يجب تحديد الخوارزمية والعملة المعينة. عمومًا، في عملية التعدين، يتم استخدام الذاكرة العشوائية لتخزين البيانات والعمليات الحاسوبية اللازمة لحساب الهاشات وإجراء عمليات التعدين. يتطلب التعدين عمومًا كمية كبيرة من الذاكرة العشوائية، وذلك لأن عملية التعدين تنطوي على حسابات معقدة ومكثفة للهاشات ويتعين تخزين البيانات المؤقتة خلال هذه العمليات. بالنسبة لاستهلاك الهاش، يعتمد ذلك على الخوارزمية والعملة الرقمية المحددة. الهاش هو عملية رياضية معقدة يتم تطبيقها على البيانات لإنشاء توقيع رقمي فريد يمثل هذه البيانات. يعتبر حجم الهاش ووقت استهلاكه أمورًا تختلف اعتمادًا على الخوارزمية المستخدمة وقوة المعالج والعملة الرقمية. لذا، لحساب متطلبات الذاكرة واستهلاك الهاش بالنسبة لعملية التعدين الخاصة بك، يجب أن تحدد الخوارزمية والعملة الرقمية التي تخطط للتعدين بها. بعد ذلك، يمكنك البحث عن المعلومات الخاصة بتلك الخوارزمية والعملة لمعرفة المتطلبات المحددة للذاكرة والهاش. سأقدم لك مزيدًا من التفاصيل حول متطلبات الذاكرة واستهلاك الهاش في عملية التعدين متطلبات الذاكرة (RAM): عملية التعدين تتطلب ذاكرة عشوائية كبيرة لمجموعة من الأسباب، بما في ذلك: حساب الهاشات: عملية التعدين تتضمن حساب الهاشات الرقمية المعقدة باستخدام البيانات المتاحة. هذه العملية تتطلب تخزين البيانات المؤقتة والمتغيرات الحاسوبية اللازمة للعمليات الحسابية. بالتالي، يحتاج المنقبون إلى ذاكرة عشوائية كافية لتخزين هذه البيانات والمتغيرات. التعامل مع الكتلة: في عملية التعدين، يجب على المنقبين التعامل مع الكتلة الجديدة وإضافتها إلى سلسلة الكتل. يحتاج ذلك إلى مساحة في الذاكرة العشوائية لتخزين الكتلة ومعالجتها قبل إضافتها بنجاح إلى سلسلة الكتل. التواصل مع الشبكة: عملية التعدين تتطلب التواصل مع شبكة العملة الرقمية المعينة، والتحقق من صحة الكتلة المعدنة ومزامنة البيانات مع الشبكة. هذا التواصل يتطلب تخزين البيانات والمعاملات المتعلقة بالشبكة في الذاكرة العشوائية. عمومًا، يجب على المنقبين تحديد متطلبات الذاكرة اللازمة لعملية التعدين وفقًا للخوارزمية والعملة الرقمية التي يستخدمونها. يمكن العثور على هذه المعلومات عادةً في الوثائق الفنية للعملة الرقمية أو في منتديات المجتمع المتعلقة بالتعدين. استهلاك الهاش: استهلاك الهاش يعتمد أيضًا على الخوارزمية والعملة الرقمية. يمكن أن يتأثر استهلاك الهاش بالعوامل التالية: قوة المعالج: التعدين يعتمد على قوة المعالج الذي تستخدمه في العملية. عمومًا، كلما كانت قوة المعالج أعلى، زاد استهلاك الهاش وزادت سرعة التعدين. الخوارزمية: كل خوارزمية تعدين تتطلب عملية معينة لحساب الهاش. بعض الخوارزميات تكون أكثر تعقيدًا وتستهلك وقتًا وموارد أكثر من غيرها. صعوبة التعدين: يتم تعديل صعوبة التعدين بناءً على الشبكة وعدد المنقبين الفعالين. عندما يزيد عدد المنقبين، يزداد سعي التنافس وصعوبة التعدين، وبالتالي يتطلب استهلاكًا أكبر للهاش لاستخراج كتلة جديدة. لحساب استهلاك الهاش، يجب أن تعرف الخوارزمية والعملة الرقمية المحددة. يمكنك العثور على معلومات حول استهلاك الهاش في الوثائق الفنية للعملة الرقمية أو من خلال مناقشات المجتمع المعني بالتعدين. يجب ملاحظة أن التعدين يتطلب أيضًا استهلاك الطاقة، والذي يعتبر عاملًا هامًا آخر يجب أخذه في الاعتبار عند التخطيط لعملية التعدين.
-
الخطأ الذي تواجهه يشير إلى محاولتك استيراد مكون ذي صلة بدون وجود حزمة رئيسية معروفة. يحدث هذا عندما تستخدم استيرادًا نسبيًا في برنامج Python الخاص بك دون تعيين حزمة رئيسية. يمكن أن يحدث هذا الخطأ إذا كنت تحاول استيراد وحدة من داخل البرنامج الخاص بك باستخدام تنسيق الاستيراد النسبي مثل from .module import function أو from ..package import module، ولكن لا يوجد حزمة رئيسية تعرف مسار الاستيراد النسبي. لحل هذه المشكلة، يمكنك اتباع الخطوات التالية: تأكد من أن ملف البرنامج الخاص بك ينتمي إلى حزمة واحدة أو مجلد رئيسي. يجب أن يكون لديك ملف __init__.py داخل المجلد الرئيسي للحزمة. استخدم الاستيراد المطلق بدلاً من الاستيراد النسبي إذا لم يكن لديك حاجة واضحة للاستيراد النسبي. بدلاً من from .module import function، يمكنك استخدام from package.module import function، حيث "package" هو اسم الحزمة الرئيسية و "module" هو اسم الموديول المراد استيراده. إذا كنت بحاجة حقًا للاستيراد النسبي ولكن لا تمتلك حزمة رئيسية، يمكنك محاولة تشغيل البرنامج من الداخل مجلد الحزمة بدلاً من خلال CMD. قم بالانتقال إلى مجلد الحزمة باستخدام أمر cd في CMD، ثم قم بتشغيل البرنامج باستخدام python your_program.py. بعد اتباع هذه الخطوات، يجب أن يكون بإمكانك تشغيل البرنامج بدون وجود خطأ "importerror attempted relative import with no known parent package".
-
وعليكم السلام! أنت على الطريق الصحيح لتصبح مطور Full Stack. عندما يتعلق الأمر بتصميم المواقع والتطبيقات، هناك بعض الخيارات التي يمكنك اتباعها: تعلم تصميم الواجهة: يمكنك التعلم عن تصميم واجهات المستخدم (UI design) لتكون قادرًا على تطوير تجارب مستخدم متميزة. يمكنك البدء بتعلم مفاهيم تصميم الواجهة والتطبيقات الجذابة، وتعلم كيفية استخدام أدوات التصميم المختلفة مثل Photoshop أو Sketch أو Figma. ستساعدك هذه المعرفة على تحويل الأفكار إلى تصميمات واقعية قبل بدء تنفيذها. العمل مع مصممين: بدلاً من تعلم تصميم الواجهة بنفسك، يمكنك التعاون مع مصممين ذوي خبرة للعمل معهم على تصميم المواقع والتطبيقات. يمكنك الاستفادة من خبرتهم ومهاراتهم في التصميم لإنشاء واجهات تتناسب مع احتياجات المشروعات التي تعمل عليها. الاستفادة من القوالب والموارد المتاحة: هناك العديد من الموارد والقوالب المتاحة على الإنترنت التي يمكنك استخدامها للحصول على أفكار وتصميمات جاهزة للمواقع والتطبيقات. يمكنك استخدام هذه القوالب كنقطة انطلاق وتعديلها وفقًا لاحتياجاتك الخاصة. بغض النظر عن الخيار الذي تختاره، من الجيد أن تكون قادرًا على فهم أساسيات التصميم ومبادئ تجربة المستخدم (User Experience - UX) لتطوير تجارب مستخدم ممتازة. قد لا تحتاج إلى أن تصبح مصممًا محترفًا، ولكن فهم أساسيات التصميم سيكون له تأثير كبير على قدرتك في تحويل الأفكار إلى واقع رقمي. لا تنسَ أنه فيما يتعلق بالتصميم، فإن التطبيق العملي والتجربة هما العنصران الرئيسيان في التطوير. قم بتطبيق ما تعلمته على مشاريعك الشخصية وتعلم من التجارب، ومع الوقت والممارسة، ستلاحظ تحسنًا في قدراتك في تصميم واجهات المستخدم. حظًا موفقًا في رحلتك في عالم Full Stack development!
- 5 اجابة
-
- 1
-
لحذف موظف من جدول الموظفين باستخدام PHP، يجب عليك استخدام لغة الاستعلامات المدمجة SQL (مثل MySQL أو PostgreSQL) لتنفيذ عملية الحذف. هناك عدة خطوات يجب اتباعها لتنفيذ ذلك: قم بإنشاء اتصال بقاعدة البيانات باستخدام معلومات اتصال صحيحة. على سبيل المثال، إذا كنت تستخدم MySQL وتريد الاتصال بقاعدة البيانات "employees" على الخادم المحلي، يمكنك استخدام الكود التالي: $servername = "localhost"; $username = "اسم_المستخدم"; $password = "كلمة_المرور"; $dbname = "employees"; // إنشاء اتصال $conn = new mysqli($servername, $username, $password, $dbname); // التحقق من نجاح الاتصال if ($conn->connect_error) { die("فشل الاتصال بقاعدة البيانات: " . $conn->connect_error); } قم بإعداد استعلام SQL لحذف الموظف من جدول الموظفين. يجب أن يتضمن الاستعلام معرف الموظف الذي تريد حذفه. على سبيل المثال، إذا كان لديك معرف الموظف في متغير يسمى $employee_id، يمكنك إنشاء الاستعلام التالي: $employee_id = 123; // تعيين معرف الموظف الذي تريد حذفه // إعداد استعلام الحذف $sql = "DELETE FROM employees_table WHERE employee_id = $employee_id"; يرجى ملاحظة أن "employees_table" هو اسم جدول الموظفين الخاص بك، و "employee_id" هو اسم العمود الذي يحتوي على معرف الموظف في الجدول. قم بتنفيذ استعلام الحذف باستخدام الاتصال بقاعدة البيانات الذي تم إنشاؤه في الخطوة الأولى: // تنفيذ استعلام الحذف if ($conn->query($sql) === TRUE) { echo "تم حذف الموظف بنجاح"; } else { echo "حدث خطأ أثناء حذف الموظف: " . $conn->error; } قم بإغلاق اتصال قاعدة البيانات بعد الانتهاء من العمل بها: // إغلاق اتصال قاعدة البيانات $conn->close(); هذه هي الخطوات الأساسية لحذف موظف من جدول الموظفين باستخدام PHP ولغة الاستعلامات SQL. يجب عليك ضمان أنك تستبدل المعلومات الصحيحة لاتصال قاعدة البيانات وأسماء الجداول والأعمدة في الأمثلة المذكورة أعلاه وفقًا لبيئتك الخاصة.
-
الكود المعطى يحاول إنشاء دالة تسمى evenNumbers تستقبل متغيرات عددية باستخدام معامل Rest (...numbers). ومن ثم، يقوم بتكرار العناصر باستخدام حلقة for ويتحقق مما إذا كانت العناصر الفردية في الواقع أعدادًا زوجية. إذا كانت زوجية، يتم طباعتها باستخدام console.log. ومع ذلك، يوجد بعض المشاكل في الكود. دعونا نوضحها: في حلقة الـ for، يجب تحديد القيمة الأولية للمتغير i باستخدام var وتحديد الشرط للحلقة بأن يكون i أقل من numbers.length، بدلاً من i <= numbers.length. لأن المصفوفات في JavaScript تعتبر قائمة بالفهارس، ويجب أن تبدأ الفهرس من 0. بتحديد الشرط كـ i <= numbers.length، ستحصل على حلقة زائدة للفهرس numbers.length الذي لا يشير إلى عنصر صحيح في المصفوفة. بدلاً من استخدام arguments[i]، يجب استخدام numbers[i]، حيث أن المتغير numbers هو المصفوفة التي تحتوي على الأرقام الممررة كمعاملات للدالة. arguments هو كائن خاص يحتوي على جميع المعاملات الممررة للدالة، ولكن هنا لا يُستخدم بشكل صحيح. بدلاً من طباعة العنصر الموجود في حالة زوجية باستخدام console.log، يجب تخزينه في مصفوفة جديدة تحتوي على الأرقام الزوجية. وبناءً على ذلك، يمكن تصحيح الكود على النحو التالي: function evenNumbers(...numbers) { var evenArray = []; for (var i = 0; i < numbers.length; i++) { if (numbers[i] % 2 === 0) { evenArray.push(numbers[i]); } } return evenArray; } var resultArray = evenNumbers(2, 4, 6, 7, 9, 8, 11, 10); console.log(resultArray); بعد تصحيح الكود، سيتم إنشاء مصفوفة جديدة تحتوي فقط على الأرقام الزوجية [2, 4, 6, 8, 10] وسيتم طباعتها باستخدام console.log.
- 3 اجابة
-
- 1
-
ما فهمته من سؤالك ان لديك مشكلة في لون النص المعروض داخل ال Console ان كان ما تقصده هو شاشة ال consloe داخل Visual Studio ف اليك الحل إذا كانت نتائج البرنامج التي تظهر في واجهة الـ Console في Visual Studio غير واضحة أو غير مقروءة بسبب لونها الغامق وتطابقها مع لون واجهة الـ Console نفسها، فيمكنك تغيير لون النص المعروض في واجهة الـ Console باتباع الخطوات التالية: افتح مشروعك في Visual Studio. انتقل إلى قائمة "مشروع" Project من الشريط العلوي. اختر "خصائص" Properties من القائمة المنسدلة. في النافذة الجديدة، انتقل إلى القسم "التطبيق" Application. تحت قسم "واجهة مستخدم" Output type، اختر "Console Application". انتقل إلى القسم "التكوين" Configuration. في القسم "التكوين الفرعي" Subconfiguration، انقر فوق الزر "الألوان" Colors. ستظهر لك قائمة بألوان مختلفة. قم بتحديد لونٍ يتناسب مع الخلفية الحالية والذي يجعل النص مقروءًا. بعد اختيار اللون، انقر فوق زر "تطبيق" Apply ثم "موافق" OK. بعد الخطوات السابقة، يجب أن يتغير لون النص المعروض في واجهة الـ Console في Visual Studio. يمكنك تكرار الخطوات وتجربة ألوان مختلفة حتى تجد تلك التي تجعل النص سهل القراءة بالنسبة لك. اما اذا كانت المشكله موجود داخل Visual Studio Code فيمكنك اتباع الخطوات التالية إذا كنت تواجه مشكلة في قراءة النص في واجهة الكونسول في Visual Studio Code، يمكنك حل المشكلة عن طريق تعديل إعدادات الألوان في الإعدادات الخاصة بالمحرر. يمكنك اتباع الخطوات التالية: قم بفتح Visual Studio Code. انتقل إلى قائمة "File" من الشريط العلوي. اختر "Preferences" ثم "Settings" من القائمة المنسدلة. يمكنك أيضًا استخدام الاختصار Ctrl + , (فاصلة) لفتح الإعدادات. سيتم فتح نافذة الإعدادات، وستكون عبارة عن صفحة ويب تحتوي على إعدادات مختلفة. في حقل البحث في أعلى النافذة، ابحث عن "color scheme" أو "editor colors". ستظهر لك إعدادات تتعلق بألوان المحرر. انقر فوق "Edit in settings.json" أو "Edit in settings.json" بجانب إعداد الألوان المرتبطة بالمحرر. ستنتقل إلى ملف "settings.json" الذي يحتوي على إعدادات Visual Studio Code. في هذا الملف، ابحث عن إعداد "terminal.foreground" أو "console.foreground" وقم بتغيير قيمة اللون إلى لون يمكنك رؤية النص به بوضوح. يمكنك استخدام القيم الرقمية للألوان (مثل #FFFFFF للأبيض) أو اسماء الألوان المدعومة. احفظ الملف "settings.json". بعد تعديل إعدادات الألوان وحفظها، يجب أن يتغير لون النص في واجهة الكونسول في Visual Studio Code وتتمكن من قراءته بسهولة.
-
إذا كنت ترغب في إنشاء زر مع ثلاث نقاط أفقية يُطلق عليها القائمة المنبثقة عند النقر عليها، يمكنك استخدام مكوّن القائمة المنبثقة المتاح في مكتبة Bootstrap. هنا هو كيف يمكنك القيام بذلك: قم بتضمين مكتبة Bootstrap في مشروعك. يمكنك تنزيلها واستخدامها من موقع Bootstrap الرسمي أو استخدام CDN. استخدم العنصر div لإنشاء زر الثلاث نقاط. قم بإضافة الكلاس "dropdown" إلى العنصر div لتطبيق الأنماط اللازمة من Bootstrap. <div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <!-- زر الثلاث نقاط --> ... </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <!-- محتوى القائمة المنبثقة --> <button type="button" class="dropdown-item" href="#">زر 1</button> <button type="button" class="dropdown-item" href="#">زر 2</button> </div> </div> قم بتعديل المحتوى داخل زر الثلاث نقاط بحسب احتياجاتك، مثل استخدام رمز أيقونة ثلاث نقاط. قم بإضافة العناصر التي ترغب في وضعها داخل القائمة المنبثقة بين عناصر div ذات الكلاس "dropdown-menu". يمكنك استخدام العنصر button لإنشاء زر داخل القائمة المنبثقة. تأكد من أنك قمت بتضمين ملفات JavaScript وCSS الخاصة بـ Bootstrap في مشروعك لتفعيل الوظائف اللازمة. بعد تنفيذ الخطوات السابقة وتشغيل مشروعك، عند النقر على زر الثلاث نقاط، ستظهر القائمة المنبثقة التي تحتوي على الأزرار الأخرى.
- 4 اجابة
-
- 1
-
1- useCallback: useCallback هو هوك في React يُستخدم لتحسين أداء تطبيق React عند استخدام الدوال في العناصر النائبة (components). يقوم useCallback بتخزين الدالة المُعطاة وإرجاع نسخة محسنة منها عندما يتغير أحد الاعتماديات المُعطاة له. في حالات عادية عندما يتم إعادة تقديم العنصر النائب يتم إعادة إنشاء الدوال المعطاة له مرة أخرى. ومع استخدام useCallback، يمكن تجنب هذا السلوك وتقليل عمليات الإعادة اللازمة. يساعد في تحسين أداء التطبيق بشكل عام. مثال على استخدام useCallback: import React, { useCallback } from 'react'; function MyComponent() { const handleClick = useCallback(() => { console.log('Button clicked!'); }, []); return <button onClick={handleClick}>Click me</button>; } في المثال أعلاه، يتم استخدام useCallback لتجنب إعادة إنشاء الدالة handleClick عند إعادة تقديم العنصر النائب. تم تمرير قائمة الاعتماديات الخاوية []، مما يعني أن الدالة لا تعتمد على أي قيم، وبالتالي يتم إرجاع نسخة منها دون تغيير عند إعادة التقديم. 2- useMemo: useMemo هو هوك في React يُستخدم لتحسين أداء تطبيق React عند استخدام القيم المُحسوبة (computed values). يقوم useMemo بتخزين القيمة المُحسوبة وإرجاع نسخة محسنة منها عندما يتغير أحد الاعتماديات المُعطاة له. عند استخدام القيم المحسوبة في تطبيق React، قد يتم إعادة حسابها في كل إعادة تقديم للعنصر النائب، وهذا يمكن أن يؤدي إلى تأثير سلبي على أداء التطبيق. باستخدام useMemo، يمكن تجنب إعادة حساب القيم المحسوبة إلا عندما يتغير أحد الاعتماديات المُعطاة له. مثال على استخدام useMemo: import React, { useMemo } from 'react'; function MyComponent() { const expensiveValue = useMemo(() => { // Some expensive computation return computeExpensiveValue(); }, [dependency1, dependency2]); return <div>{expensiveValue}</div>; } في المثال أعلاه، يتم استخدام useMemo لتجنب إعادة حساب القيمة المكلفة expensiveValue في كل إعادة تقديم للعنصر النائب. تم تمرير قائمة الاعتماديات [dependency1, dependency2]، وعندما يتغير أحد الاعتماديات يتم إعادة حساب القيمة المكلفة وتحسين الأداء بشكل عام. يمكنك التوسع في معرفة تفاصيل اكثر من خلال هذا الرابط بالاضافة الي التطبيق العملي
-
Hooks هي ميزة مهمة في مكتبة React التي تسمح لك بإضافة حالة (state) وميزات أخرى إلى المكونات الوظيفية (Functional Components). تسهل الـ Hooks إدارة الحالة والحصول على دورة حياة المكونات وإجراءات أخرى داخل المكونات الوظيفية بطريقة أكثر بساطة وقابلية لإعادة الاستخدام. وهنا أشرح بإيجاز كل Hook ووظيفته: useState Hook: يستخدم لإضافة حالة (state) إلى المكونات الوظيفية. يسمح لك بتعريف متغير وتحديث قيمته داخل المكونة. useEffect Hook: يستخدم لتنفيذ أعمال جانبية (side effects) في المكونات الوظيفية. يسمح لك بالتعامل مع دورة حياة المكون وتنفيذ العمليات في نقاط محددة مثل التحميل الأولي للمكون أو تغيير حالة معينة. useRef Hook: يستخدم للوصول إلى عناصر DOM أو الحفاظ على قيم داخل المكونات الوظيفية عبر إعادة التقديم (re-rendering) دون أن يؤدي إلى تغيير قيمة الحالة وإعادة التجديد. useCallback Hook: يستخدم لتجنب إعادة إنشاء الدوال في كل تقديمة جديدة للمكونة. يمكن استخدامه لتحسين الأداء عند تمرير دوال كخصائص إلى المكونات الفرعية. useMemo Hook: يستخدم لتخزين القيم المحسوبة (computed values) وتجنب إعادة حسابها في كل تقديمة جديدة للمكونة. يمكن استخدامه لتحسين الأداء عند الحاجة إلى حساب قيم مكلفة الوقت. useContext Hook: يستخدم للوصول إلى القيم المشتركة عبر كل شجرة المكونات بدون الحاجة إلى تمريرها عبر الخواص (props). يسمح لك بالوصول إلى السياق (context) المحدد في أي مكان داخل التطبيق. useReducer Hook: يستخدم لإدارة الحالة المعقدة وتنفيذ إجراءات (actions) في المكونات الوظيفية. يوفر طريقة لتحديد حالة المكون بواسطة توجيه أوامر (dispatching actions) وتحديد الحالة الجديدة. تتيح لك هذه الـ Hooks استخدام وظائف وميزات متقدمة في المكونات الوظيفية وتسهل إدارة حالة التطبيق وإجراء العمليات الجانبية والوصول إلى السياق وإعادة استخدام الأكواد.
-
forEach(), map(), filter(), وreduce() هي وظائف جداول JavaScript التي تستخدم للتعامل مع البيانات في مصفوفة وتنفيذ عمليات عليها. وإليك شرحًا لكل منها والفروق بينهم: forEach(): وظيفة forEach() تُسمح لك بتنفيذ وظيفة محددة على كل عنصر في المصفوفة. لا تعيد أي قيمة ولا تقوم بإنشاء مصفوفة جديدة. const names = ["John", "Jane", "Mike"]; names.forEach((name) => { console.log(name); }); // النتيجة // John // Jane // Mike map(): وظيفة map() تُسمح لك بتطبيق وظيفة على كل عنصر في المصفوفة وإنشاء مصفوفة جديدة بناءً على القيم المُعدلة. const names = ["John", "Jane", "Mike"]; const capitalizedNames = names.map((name) => { return name.toUpperCase(); }); console.log(capitalizedNames); // النتيجة // ["JOHN", "JANE", "MIKE"] filter(): وظيفة filter() تقوم بتصفية المصفوفة بناءً على شرط محدد وتنشئ مصفوفة جديدة تحتوي فقط على العناصر التي تمر بالشرط المحدد. const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const evenNumbers = numbers.filter((number) => { return number % 2 === 0; }); console.log(evenNumbers); // النتيجة // [2, 4, 6, 8, 10] reduce(): وظيفة reduce() تستخدم لتجميع قيم المصفوفة إلى قيمة واحدة واحدة. تنفذ وظيفة معينة على كل عنصر في المصفوفة وتستخدم القيمة المرجعة من العملية السابقة في العملية التالية. const numbers = [1, 2, 3, 4, 5]; const sum = numbers.reduce((accumulator, number) => { return accumulator + number; }, 0); console.log(sum); // النتيجة // 15 هذه الأمثلة توضح كيفية استخدام كل وظيفة (forEach(), map(), filter(), و reduce()) للتعامل مع المصفوفات وتنفيذ العمليات عليها بشكل مختلف. تتيح لك هذه الوظائف التلاعب بالبيانات بسهولة وإنشاء مصفوفات جديدة أو تحويل البيانات إلى شكل مرغوب. يمكنك التوسع في فهم هذه المفاهيم من خلال التطيبق عليها واستخدامها المكثف.