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

Adnane Kadri

الأعضاء
  • المساهمات

    5256
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    52

كل منشورات العضو Adnane Kadri

  1. يمكنك تضمين useLocation من @reach/router و من ثم قراءة القيمة على هذا النحو : import * as React from 'react'; import { useLocation } from '@reach/router'; const Current = () => { const location = useLocation(); console.log(location); }; سيتم طباعة كائن يسهل قراءة الخواص منه على هذا النحو : { pathname: "/", href: "http://localhost:8000/", origin: "http://localhost:8000" }
  2. يمكنك استبدال المسار الأخير (تأكد أنه الأخير دوما) على هذا النحو : <Route component = {NotFound} /> // هذا <Redirect to="/" /> // بهذا سيتم تتبع كل المسارات التي تختلف عن المسارات التي هي ما قبل هذا المسار و بدل عرض مكون react سيعاد توجيه المستخدم إلى الصفحة الرئيسية . و يمكنك عمل ذلك عن طريق مكتبة Gatspy على هذا النحو : ليكن في العلم أن صفحة 404 المنشئة من طرف المكتبة تكون بـ src/pages/404.jsx أو src/pages/404.js يمكنك تعديلها على هذا النحو لتقوم بنفس المهمة : import React from 'react' import { navigate } from 'gatsby' const NotFoundPage = () => { return navigate('/') } export default NotFoundPage
  3. هل يمكنك ذكر نوع محرر النصوص الذي تستخدمه ؟ أو على الأقل إرفاق صورة لذلك
  4. و هذا هو دور مطوري الواجهة الخلفية و قواعد البيانات . فهم المسؤولون عن جعل عملية إضافة المنتجات ( أو أي نوع اخر من المدخلات ) في قاعدة البيانات و التحكم بها عملية بسيطة من خلال واجهة إدخال يهتم مطور الواجهة الأمامية بتصميمها . يستعملون لإدارة قواعدة البيانات أشياء من مثل MySQL , MongoDB , Oracle , SQLServer , Redis .. الخ . أو ربما بعض اليات التخزين المؤقتة من مثل varnish , Memcached , redis .. الخ . و يحتاجون على الأقل للغة برمجة لهندسة الواجهة الخلفية و تولي كل الأشياء التي تحدث على مستوى الخادم . لغات من مثل Java , Python , Ruby , Php , .net .. الخ . فالمواقع من مثل مثالك لا تكتمل إلا بجزئيها و واجهتيها , الأمامية و الخلفية .
  5. تقريبا هي نفس العملية و كل خطوة من الاتي تتبع نفس منطق كل خطوة من التعليق السابق . بداية يجب عليك الإتصال بقاعدة البيانات <?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDB"; // إنشاء اتصال $conn = new mysqli($servername, $username, $password, $dbname); // تفحص الإتصال و طباعة الأخطاء ان وجدت if ($conn->connect_error) { die("فشل الإتصال بقاعدة البيانات: " . $conn->connect_error); } كتابة الإستعلام بشكل string : <?php $sql = "INSERT INTO YourTableName (column1, column2, column3) VALUES ('value 1', 'value 2', 'value 3')"; عمل Excution للإستعلام المطبوع حديثا : <?php if ($conn->query($sql) === TRUE) { echo "تم ادراج عنصر جديد بقاعدة البيانات"; } else { echo "خطأ: " . $sql . "<br>" . $conn->error; } فيكون الكود كاملا : <?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDB"; // إنشاء اتصال $conn = new mysqli($servername, $username, $password, $dbname); // تفحص الإتصال و طباعة الأخطاء ان وجدت if ($conn->connect_error) { die("فشل الإتصال بقاعدة البيانات: " . $conn->connect_error); } // طباعة إستعلام $sql = "INSERT INTO YourTableName (column1, column2, column3) VALUES ('value 1', 'value 2', 'value 3')"; // تنفيذ الإستعلام if ($conn->query($sql) === TRUE) { echo "تم ادراج عنصر جديد بقاعدة البيانات"; } else { echo "خطأ: " . $sql . "<br>" . $conn->error; } و قد تحتاجين إغلاق الإتصال أحيانا , يمكنك ذلك عن طريق : <?php // تنفيذ إغلاق الإتصال $conn->close();
  6. هل يمكنك تفعيل الDebug Mode و إرفاق الأخطاء التي ظهرت ؟ سيساعد هذا في حل المشكل أكثر يمكنك ذلك عن طريق تعديل ملف php.ini . قم بتغيير قيمتي error_reporting و display_errors , إلى : error_reporting = E_ALL display_errors = On ملاحظة : طبعا لا ينبغي وضع الأكواد حرفيا فهي وصفية و إنما يجب صياغة نفس المنطق في كتابة كود مشابه أو تنسيق الكود بما يلائم تضمينه
  7. هل يمكنك وصف المشاكل التي واجهتها أو أي أخطاء ظهرت ؟
  8. بإستخدام phpmyadmin يمكنك ذلك عن طريق : التصفح إلى http://localhost/phpmyadmin الدخول إلى قاعدة البيانات المقصودة بالقائمة الجانبية . الضغط على زر SQL في قائمة التصفح أعلى الصفحة . طباعة إستعلام الإدراج و الضغط على GO , يكون كود الإستعلام على هذا النحو : INSERT INTO blood_groups (blood_group_name) VALUES ('O+'); INSERT INTO benefactor (fk) VALUES (/* من جدول الفصائلid قم بطباعة اخر */); ملاحظات : يجب مراعاة القيم الإفتراضية للأعمدة بالجداول السابقة و التأكد من أن لها قيم إفتراضية بالفعل . لا ينصح بإدخال البيانات يدويا إلا في حالات إستثنائية , عوضا عن ذلك يمكنك فعل ذلك بالـ php .
  9. كل الخطوات صحيحة و سليمة , يبدوا أن المشكلة في إستعمال سرفر smtp . قم بتغيير العنوان إلى : smtp.googlemail.com أي MAIL_HOST بملف الإعداد على هذا النحو : MAIL_DRIVER=smtp MAIL_HOST=smtp.googlemail.com MAIL_PORT=465 MAIL_USERNAME=YOUR_EMAIL_ADDRESS MAIL_PASSWORD=PASSWORD MAIL_ENCRYPTION=ssl و لا تنسى محو الكاش : php artisan cache:clear php artisan config:cache
  10. لو أحببت أن تترك الأمر لجانب الباك اند فقط فيمكنك تطبيق العملية وفق المنطق التالي : جلب كل العناصر الغير مميزة . جلب العناصر المميزة . تكرار العناصر المميزة كذا مرة . دمج العناصر المميزة مع غير المميزة وفق ترتيب معين . مثال عملي : يمكنك جلب كل العناصر التي لا تحتوي على 1 في حقل المنتج المميز على هذا النحو : $sql = "SELECT * FROM Prodect WHERE is_special = 0 ORDER BY RAND()"; ثم جلب العناصر المميزة و تكرارها : <?php // تحضير الاستعلام $sql2 = "SELECT * FROM Prodect WHERE is_special=1 ORDER BY RAND()"; function getRepeated($query) { $repeat_times = 10; $counter = 0; $rows = []; $result = mysql_query($query); // تحضير كل الحقول while($row == mysql_fetch_row($result)) { $rows[] = $row; } // تحضير مصفوفة تحمل عناصر مميزة ومكررة $repeated = []; for($index = 0; $counter < $repeat_times; $counter++) { $repeated[] = $rows[$i]; $index++; // إعادة الدور إلى الصفر لملئ المصفوفة بعناصر مكررة if($index == count($rows)) { $index = 0; } } return $repeated; } $special = getRepeated($sql2); المزج وفق الترتيب و التكرار : <?php $non_special = [...]; // ناتج الاستعلام الاول $special = [...]; // ناتج الاستعلام الثاني مكرر $total = []; $offset = 0; for($i = 0; $i < count($non_special); $i++) { if(is_float($i / 10)) { array_push($total ,$non_special); } else { // قطعة من مصفوفة المنتجات المميزة لدمجها $pieceOfSpecial = array_slice($special,$offset,5); $offset += 5; array_merge($total ,$pieceOfSpecial); } } // =======> return $total الان ستسهل عملية عرضها مباشرة تحديث : يمكن أن لا تكون هناك أي حاجة من تكرار العناصر المميزة كذا مرة لدمجها مع الغير مميزة و يمكن تحقيق نفس الغرض في حالة جلب عدد معين من العناصر المميزة . فتكون عوض الخطوة كاملة و عوضا عن اقتطاع المصفوفة كل مرة في المرحلة الأخيرة يمكنك فقط دمج المصفوفة كلها (قد يكون هذا البديل مفيد في حالة وجود عدد محدود جدا من العناصر المميزة بقاعدة البيانات) .
  11. تحديث : يمكنك أيضا إضافة الevents المتعلقة بالخيارات المنشئة بعد إضافتها . مثال : function setListeners(){ document.querySelectorAll('select#products option').addEventListener('click' ,function(){ // }); } ومن ثم إنشاء الأحداث بعد إنشاء العناصر : function getProducts(target) { let getProducts = new XMLHttpRequest(); getProducts.open('GET', '/invoices/getProducts/' + target); getProducts.onload = function() { if (this.readyState === 4 && this.status === 200) { // succes let products = JSON.parse(this.responseText); products.forEach(function(item) { let option = document.createElement('option'), text = document.createTextNode(item['product_name']); option.appendChild(text); option.value = item['id']; productsSelect.appendChild(option); }); setListeners(); // إستدعاء الدالة } else { alert('لقد حدث خطأ غير متوقع'); } } getProducts.send(); }
  12. يبدوا أن المشكلة في تحديد العناصر فقط : و بالفعل فإن العنصر select بالمعرف products غير موجود من ضمن الDOM . عوضا عن ذلك يوجد بالمعرف product فتكون : var productsSelect = document.getElementById('product'); ثم تحتاج إستدعاء الدالة getProducts من المكان الصحيح , أي بعد أي تغير في قائمة الأقسام على هذا النحو : <select name="section" onchange="getProducts(this.value)" class="form-control @error('section') is-invalid @enderror" id="section"> <option value="NULL" disabled>إختر القسم</option> أو أيضا : document.getElementById('section').addEventListener('change' ,getProducts(this.value)); فيكون كود الجافاسكربت كاملا على هذا النحو : var productsSelect = document.getElementById('product'); document.getElementById('section').addEventListener('change' ,getProducts(this.value)); function getProducts(target) { let getProducts = new XMLHttpRequest(); getProducts.open('GET', '/invoices/getProducts/' + target); getProducts.onload = function() { if (this.readyState === 4 && this.status === 200) { // succes let products = JSON.parse(this.responseText); products.forEach(function(item) { let option = document.createElement('option'), text = document.createTextNode(item['product_name']); option.appendChild(text); option.value = item['id']; productsSelect.appendChild(option); }); } else { alert('لقد حدث خطأ غير متوقع'); } } getProducts.send(); }
  13. بشكل عام . فكرة الكوبونات , قسائم الشراء و البرومو كودس هي أشياء يتم تقديمها للعملاء كحافز للشراء , وقد تكون خصم نسب مئوية معينة ,خصم مبلغ معين ثابت أو حتى الشحن و التوصيل المجاني و ربما أفكار أخرى . أما إن كنت تقصد الكوبونات كمفهوم برمجي فيمكن معاملتها كغيرها من المفاهيم و من ثم إستعمالها في عمليات حساب سعر المنتج و الدفع . مثال عملي عن الإستعمال : قم بإنشاء جدول كوبونات بقاعدة البيانات يحوي الأعمدة : coupon_code // معبرا عن كود الكوبون coupon_type // معبرا عن نوع الكوبون coupon_amount // معبرا عن مقدار الخصم بحيث ينحصر نوع الكوبون في الأنواع الثلاثة الممثلة بأرقام 1,2,3,على التوالي , بـ : 1 => fixed_card_amount // مبلغ خصم ثابت 2 => percentage_off // خصم نسبة مئوية 3 => free_shipping // شحن مجاني 2. في نموذج إدخال كود الكوبون بصفحة الدفع قم بالتحقق من وجود كوبون يحمل نفس الكود المدرج أو لا . 3. إن كان نعم يمكنك تحديد نوع و مقدار الكوبون . 4. و من ثم عمل العملية الحسابية لحساب السعر الجديد و إظهاره للمستخدم . (طبعا يجب أخذ الحيطة و إدراج إحتمال التلاعب بالسعر و التصرف وفق ذلك , مثال :تخزين السعر في الباك اند بعد إدخال كود كوبون أكثر أمانا ) . طبعا هذا هو الشكل الأبسط للعملية , و هي وصفية بحتة يمكنك تطبيقها باللغة التي تبرمج وفقها . كما يمكنك إضافة الكثير من المميزات مثل : كوبون للمسجلين حديثا فقط , كوبون بتاريخ إنتهاء صلاحية , كوبون بعدد منتهي للإستعمال .. إلخ .
  14. الوظيفة openssl_cipher_iv_length هي جزء من مكتبة openSSL PHP المضمنة في اعتمادات الphp بالفعل . في حالات قد يكون هذا الإمتداد مثبتا بالفعل , فيمكنك مباشرة تفعيله عن طريق تعديل ملف الإعداد php.ini مثل ما قام الأخ @يوسف احمد9بالإشارة . إن لم تحل المشكلة يستحسن تحديث إعتمادات اللارافل الخاصة بالمشروع , يمكنك ذلك عن طريق الأمرين : composer install composer update و في أحيان أخرى لن يكون الإمتداد مثبتا و هذا قد يدفعك إلى تحميل ملف الـ dll الخاص بالإضافة ( ssleay32.dll ) و من ثم إضافته إلى مجلد الphp . ملاحظات : قد تحتاج إعادة تشغيل السرفر في هذا الأمر أو الأمر الأول .
  15. يمكنك إرسال طلب إلى نقطة الوصول هاته للتحويل من عملة معينة إلى أخرى : https://data.fixer.io/api/convert ? access_key = API_KEY & from = GBP & to = JPY & amount = 25 كما يمكنك جلب معدلات التحويل بالنسبة لعملة رئيسية عن طريق هاته النقطة : https://data.fixer.io/api/2013-12-24 ? access_key = API_KEY & base = USD & symbols = JPY,CAD,EUR,DZD لاحظ أنه قم تم تخصيص تاريخ معين يتم فيه جلب معدل التحويل الخاص بذاك التاريخ . يمكنك جعل العملية ديناميكية عن طريق : const date = new Date().toISOString().slice(0, 10); ثم تمرير الثابت date . لاحظ أيضا أنه يمكنك تخصيص العديد من العملات في مرة واحدة و هذا شيء جميل . مثال عن رد من التوثيق الرسمي للواجهة : { "success": true, "historical": true, "date": "2013-12-24", "timestamp": 1387929599, "base": "GBP", "rates": { "USD": 1.636492, "EUR": 1.196476, "CAD": 1.739516 } }
  16. أسعار العملات بالنسبة لعملة رئيسية و معدلات التحويل الخاصة بها متغيرة في الغالب و تحتاج ديناميكية لوضع الأسعار . تستطيع إما تخزين السعر بالدولار كـ base currency و من ثم جعل عملية التحويل ديناميكية عن طريق معدل تحويل . لا أظن أنه توجد حزمة جاهزة لتقوم بالعملية . لكن يمكنك إستعمال أحد هاته الـ APIS : هذا أو هذا لجلب معدلات التحويل من الدولار أو من أي base currency تستعملها . كما يمكنك مباشرة إرسال طلبات GET إلى نقطة الوصول هاته فقط و قراءة الخاصية geoplugin_currencyConverter لجلب معدل التحويل الذي يخص بالمستخدم نفسه (الذي تم إرسال الطلب عن طريقه) من الدولار من الرد مباشرة أيضا (مثلا لإظهار العملة بحسب بلد المستخدم حسب تحليل الـ IP) . أيا كانت طريقتك في جلب معدل التحويل يمكن حساب السعر الجديد بسهولة عن طريق : var new_price = base_price * exchange_rate_base_to_target /*من الرسبونس*/; و كإقتراح لتحسين تجربة المستخدم و جعل عملية تثبيت العملة المحول إليها سهلة , قم بتخزين العملة و معدل التحويل في الجلسة أو الكوكي أو التخزين المحلي بدل إرسال طلب مع كل مرة . ملاحظات : يمكنك أيضا الإستغناء عن هاته العملية ككل و إدخال أسعار لمختلف العملات في حالة كان عدد العملات محدود جدا و تريد تحكم أكبر في الأسعار بحسب البلد أو العملة (خذ إحتمال أسعار السوق السوداء مثلا , فهي لا ترسل في الردود من أي API و قد تحتاجها لوضع تسعيرة معقولة في حال كان هنالك تباعد كبير بين سعر الصرف و سعر السوق السوداء) . و بنفس منطق واجهات التطبيق البرمجية المشار إليها يمكنك تخصيص نقطة وصول لجلب معدلات التحويل بتطبيقك نفسه و ليكن من جدول تنشأه : معدلات التحويل exchange_rates , و من ثم التحكم في هاته المعدلات على نطاق أوسع و التعديل بما يلائم سعر الصرف الحالي أو السعر الذي يناسب فرع المتجر بالعملة الفلانية .
  17. يمكنك رفع الملفات من المشروع إلى المستودع المحلي عن طريق اﻷمرين : أولا : // إضافة كل الملفات المعدلة git add -A // إضافة ملفات محددة git add changedDirectory // أو git add changedFile ثم : git commit -m "A changes title" و أخيرا رفع الملفات إلى الـبرانش الخاص بك على الـ remote repo عن طريق : git push -u origin yourBranch ستلاحظين اخر commit قمت بعمله على المستودع الخاص بك على هذا النحو :
  18. لك الخيار في أن تقوم مباشرة بإستعمال المكتبة التي تقدمها و ربطها مع الـ Laravel كمكتبة خارجية أو بإستعمال أحد الحزم التي تبسط العملية . ولعل هاته الحزمة الأفضل على الإطلاق.
  19. لا حاجة لتشفير الـ ID لحل المشكلة فعليا , عوضا عن ذلك يمكنك إنشاء دالة أو middleware يقوم بالتحقق من ملكية العنصر item قبل عمل أي تعديلات عليه . مثال عملي : <?php class YourController extends Controller { public function editItem(Request $request ,Item $item){ if(! $this->isOwner($item)){ return 'لا يمكنك تعديل العنصر'; } // تكملة العملية } private function isOwner($item){ if(auth()->user()->id == $item->user_id){ return true; } return false; }
  20. في العادة إرسال رسائل sms قد تحتاج تكلفة و إشتراك لتطبيق العملية و الإستعانة بها. و يمكنك تطبيق العملية كلها وحدك مثل ما أشار الأخ @بلال زيادة. وقد تحتاج الإستعانة بأحد هاته الواجهات Twilio أو Plivo . مثال عن إرسال رسالة بإستعمال Twilio : <?php use Twilio\Rest\Client; # إرسال رسالة ... $client = new Client($account_sid, $auth_token); # تعطى مع حساب تويليو $client->messages->create($receiverNumber, [ 'from' => $twilio_number, # يعطى مع حساب تويليو 'body' => $activation_code ]); # قم تخزين الكود ... $currentUser->update([ 'activation_code' => $activation_code , ]); ثم براوت اخر يمكنك عمل المصادقة بشكل مشابه : <?php ... if($user_input == $activation_code){ $current_user->update([ 'phone_is_activated' => true, ]); return 'أنت مفعل'; } return 'كود التفعيل خاطئ'; و بالطبع فإن هذا هو الشكل الأبسط للعملية , يمكنك إضافة العديد من الأشياء كإنتهاء صلاحية الكود أو ربط كود التفعيل بمودل اخر غير مودل المستخدم و غيرها . كما يمكنك إستعمال حزم جاهزة مثل هاته الحزمة بحيث توفر عليك الكثير من الأشياء من مثل الError Reporting و كل الBack end Logic بحيث تقوم بإرسال بيانات إلى نقاط وصول معينة و القراءة من الرد . و مثل ما تقدم هذا في نفس الوقت هي تزيل عنك حرية التصرف و التطوير بما يلائم مشروعك .
  21. يبدوا أن المشكلة فقط في تعريفك للـ Routes فلو كانت المشكلة في إظهار الview فسيتم رمي exception عن طريق ViewException من داخل المتحكم . فهذا يعني أن الطلب لا يصل أصلا إلى المتحكم و المشكلة فقط هي في سطر واحد . Route::get('user/profile', [UserConroller::class, 'edit']); وبالفعل فأنت تستخدم تعريفا من النسخة 8 من لارافل في حين أنك تستخدم لارافل 5 و تقوم بإستعمال سياق غير مدعم بعد (PHP callable syntax) على هذا النحو : <?php use App\Http\Controllers\UserController; .. Route::get('user/profile', [UserController::class, 'edit']); // غير مدعوم بعد في حين أنه في النسخ ما قبل 8.x يجب عليك تعريف الراوت على هذا النحو (string syntax) : <?php Route::get('user/profile', 'UserController@edit'); و ستحل المشكلة بهذا . ملاحظات : مثل ما شرح الزملاء فإنه يوجد لديك بعض الأخطاء يجب إصلاحها و ذلك في UserConroller تصبح UserController و في oute تصبح Route و هذا : <?php public function edit() { # $user = User::find(auth()->user()->id); عوضا عن هذا $user = auth()->user(); # هذا /* * ولا داعي لتمرير المتغير يوزر أصلا * بحيث يمكنك استعمال هذا المساعد * auth() * بداخل ملفات الblade */ return view('auth.profile',compact('user')); } بعد ذلك , وكخطوات إضافية , تأكد أن تقوم بمحو الكاش عن طريق : php artisan route:clear ثم تأكد أن الراوت موجود عن طريق : php artisan route:list و أخير يمكنك التصفح إلى http://127.0.0.1:8000/user/profile كعضو مسجل و استعراض الصفحة .
  22. هل يمكنك إرفاق ملفات المشروع أو على الأقل معلومات أكثر عن المشكلة ؟
  23. إن كنت تعتمد على تخزين محلي فقط يمكنك تخزين الملفات إما في الـ public_path أو الـ storage_path . في الحالة الأولى ستكون جميع الملفات و الصور المخزنة ظاهرة للعامة و يمكن الوصول إليها ببساطة . تخزن الملفات في : public > your-folder و يكون التخزين على هذا النحو : <?php .. $request->file('image')->move(public_path('your-folder'), $name); في الحالة الثانية لن يمكن إستدعاء الصور و الملفات إلا عن طريق إنشاء رابط symlink و هاته الطريقة أكثر أمانا و حفظا للخصوصية في حالة ما كانت الملفات و الصور المخزنة حساسة أو خاصة . افتراضيا يتم تخزين هاته الصور و الملفات في : storage > app > public > your-folder و التخزين على هذا النحو : <?php .. $request->file('image')->move(storage_path('your-folder'), $name); علما أنه يمكنك إدارة و إنشاء ديسكات التخزين بملف config/filesystems.php : <?php ... 'disks' => [ ... 'storage-path' => [ 'driver' => 'local', 'root' => storage_path('app').'/uploads', ], 'public-path' => [ 'driver' => 'local', 'root' => public_path().'/uploads', 'url' => env('APP_URL').'/public_files', 'visibility' => 'public', ] ... ], ملاحظة : يمكنك إنشاء الsymlink عن طريق طباعة الأمر : php artisan storage:link
  24. بداية , لا يمكنك تخزين أي ملفات بقاعدة البيانات Sql , عوضا عن ذلك يمكنك إستخدام الfile systems لتخزين الصورة أو الملف و تخزين باث الصورة أو الملف في قاعدة البيانات . يتم إستقبال الطلب من قبل اللارافل و معالجته على هذا النحو : <?php public function uploadImg(Request $request) { // التحقق إن كان الطلب يحمل ملف باسم image if($request->hasFile('image')) { // انشاء اسم بلاحقة للملف $name = time()."_".$request->file('image')->getClientOriginalName(); // تخزين الملف بالpublic path $request->file('image')->move(public_path('images'), $name); } // return response()->json([ asset("images/$name"), // باث الصورة 201, // كود الحالة 'message' => asset("images/$name") ? 'تم حفظ الصورة' : 'failed' ]); }
  25. يمكنك الإستعانة بهاته الحزمة لتحقيق الغرض. بداية قم بتثبيت الحزمة عن طريق مدير الحزم : npm install react-ga --save 2. تضمين الموديلات اللازمة بملف App.js : import ReactGA from "react-ga"; 3. مصادقة غوغل انالتكس مع الحزمة , أيضا قم بتعريف ثابت بشكل globally (سنأتي لإستعماله في الخطوة التالية): ReactGA.initialize("TRACKING-ID"); const history= createHistory(window); 4. بداخل وسم LocationProvider بالراوتر قم بتعريف الخاصية history و قم بإرفاقها بالثابت الذي تم تعريفه على هذا النحو : <LocationProvider history={history}> <Router> .. </Router> </LocationProvider> الان يتم رصد أي تغيير يخص الكائن window . ينبغي الان فقط الإستماع لهاته التغيرات و التصرف بناءا عليها . مثال : history.listen( window => { ReactGA.pageview(window.location.pathname + window.location.search); }); و هذا جواب سؤالك :
×
×
  • أضف...