لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 10/14/21 في كل الموقع
-
السلام عليكم ماهي افضل الادوات لبناء موقع ويب وفي نفس الوقت يكون متاحا على شكل تطبيق شكرا1 نقطة
-
1 نقطة
-
لدي بيانات من ملفين وأريد رسم هيستوغرامين لتمثيلهما، لكن أريد أن يكونان على نفس المخطط. في البداية قمت برسم هستوغرام لبيانات من ملف واحد، ونجح الأمر لكن الآن أحاول رسم هستوغرام فوقه (تراكب) من ملف آخر. لكن لم ينجح الأمر هل من مساعدة؟ حيث أن المشكلة هي أنه بالنسبة لكل مجال للقيم، يظهر الشريط ذو القيمة الأعلى فقط، والآخر يكون مخفياً.1 نقطة
-
لدي plot وأريد جعل لون خلفية له سوداء، كيف يمكنني تغييرها؟ علماً أنني حاول استخدام set_facecolor لكن ظهر كما في الصورة فما السبب وما الحل؟ import numpy as np import matplotlib.pyplot as plt x = np.random.normal(1, 2, 5000) y = np.random.normal(-1, 3, 2000) bins = np.linspace(-10, 10, 30) fig = plt.figure() fig.patch.set_facecolor('black') plt.hist([x,y], bins = 15,label=[x,y],color=["red","blue"]) legend = ['Data1','Data2'] plt.legend(legend) plt.show()1 نقطة
-
مرحبا, احاول اضافة بوابة الدفع utrust في لارافيل, نفذت كل الخطوات تبقت لي فقط التحقق من عملية الدفع اذا تمت او لا عن طريق حدث wibhook يتم ارساله من منصة utrust, ما لم افهمه هو كيف احصل على المعلومات المتواجدة في المتغير $payload, مشروح ذلك في التعليق لكن لم افهم كيف يتم فعل ذلك في لارافيل,(او بصيغة اخرى بماذا استبدل المتغير $payload) هذا مثال php من المكتبة الخاصة بهم: https://github.com/utrustdev/utrust-php/blob/master/examples/validate_webhook.php و التوثيق :https://docs.api.utrust.com/#tag/Webhooks1 نقطة
-
إن PHP ليس لديها طريقة مثل GET و POST لاستقبال البيانات على شكل طلبية PUT أو غيرها لذلك تتعامل معهم على شكل مختلف: لذلك نستخدم php://input لقراءة بيانات الطلبية نستقبلهم كملف، ثم نحول المحتوى عن طريق parse_str parse_str(file_get_contents("php://input"),$payload); echo $payload['success']; // true حسب التوثيق نجاح الطلبية يعيد { success: true } parse_str تستقبل سلسلة نصية وتعيد إما متغيرات لكل مفتاح/قيمة أو تعيد مصفوفة في حال تمرير وسيط ثاني: <?php parse_str("name=WAEL&age=25"); echo $name."<br>"; echo $age; ?> <?php parse_str("name=WAEL&age=25",$myDataArray); print_r($myDataArray); ?>1 نقطة
-
الحل كالتالي: from matplotlib.ticker import PercentFormatter import matplotlib.pyplot as plt import numpy as np from matplotlib import colors # إنشاء بيانات عشوائية N_points = 98 n_bins = 15 # إنشاء توزيع يمثل بيانات أول هيستوغرام x1 = np.random.randn(N_points) # إنشاء توزيع يمثل بيانات الهستوغرام لثاني x2 = np.random.randn(N_points) # تعريف الحاوية fig, axs = plt.subplots(1, 1, figsize =(10, 7), tight_layout = True) # ticks حذف العلامات axs.xaxis.set_ticks_position('none') axs.yaxis.set_ticks_position('none') # إضافة شبكة إلى الخلفية axs.grid(b = True, color ='y', linestyle ='-.', linewidth = 0.5, alpha = 0.6) # plot حذف خطوط حاويةال for s in ['top', 'bottom', 'left', 'right']: axs.spines[s].set_visible(False) #وضع مسافة بين التسميات وبين المحاور axs.xaxis.set_tick_params(pad = 4) axs.yaxis.set_tick_params(pad = 8) # إنشاء الهستوغرامين معاً axs.hist([x1,x2], bins = n_bins,label=[x1,x2],color=["red","black"]) # تسمية للمحاور plt.xlabel("X-axis") plt.ylabel("y-axis") legend = ['File1','File2'] plt.legend(legend) # عنوان plt.title('Hsoub') # عرض plt.show() الخرج: حيث قمنا بتمريرهم إلى نفس دالة hist كما فعلت، حيث تقوم الدالة برسم الأعمدة التي تحدد تكرار نفس القيم بجانب بعضها بدل أن تقوم بجعلها فوق بعضها من خلال استخدام دالتين لرسم كل هيستوغرام وبالتالي يصبح المخطط غير مقروء أو صعب القراءة كما في الكود التالي (بنهاية الأمر اختر ماتراه مناسباً لك): from matplotlib.ticker import PercentFormatter import matplotlib.pyplot as plt import numpy as np from matplotlib import colors # إنشاء بيانات عشوائية N_points = 98 n_bins = 15 # إنشاء توزيع يمثل بيانات أول هيستوغرام x1 = np.random.randn(N_points) # إنشاء توزيع يمثل بيانات الهستوغرام لثاني x2 = np.random.randn(N_points) # تعريف الحاوية fig, axs = plt.subplots(1, 1, figsize =(10, 7), tight_layout = True) # ticks حذف العلامات axs.xaxis.set_ticks_position('none') axs.yaxis.set_ticks_position('none') # إضافة شبكة إلى الخلفية axs.grid(b = True, color ='y', linestyle ='-.', linewidth = 0.5, alpha = 0.6) # plot حذف خطوط حاويةال for s in ['top', 'bottom', 'left', 'right']: axs.spines[s].set_visible(False) #وضع مسافة بين التسميات وبين المحاور axs.xaxis.set_tick_params(pad = 4) axs.yaxis.set_tick_params(pad = 8) # إنشاء الهستوغرام الأول axs.hist(x1, bins = n_bins,alpha=0.8) # إنشاء الهستوغرام الثاني axs.hist(x2, bins = n_bins,color="red",alpha=0.7) # تسمية للمحاور plt.xlabel("X-axis") plt.ylabel("y-axis") legend = ['File1','File2'] plt.legend(legend) # عنوان plt.title('Hsoub') # عرض plt.show() الخرج:1 نقطة
-
1 نقطة
-
عليك استخدام بيئة برمجية Cross Platform أي أنها تعمل على عدة منصات (أنظمة تشغيل) ويوجد العديد منهم، ملاحظة: في كل فترة تحدث تطويرات وقد تدعم البيئة منصات أكثر في المستقبل.. Flutter وتعمل بلغة Dart وتعمل على جميع المنصات android - ios - web - windows - mac .. React Native تعمل بلغة JavaScript بالإضافة للغات الويب HTML - CSS وتعمل أيضا على مختلف المنصات android - ios - web .. تقنيات هجينة Hybrid: Cordova تعمل بلغة JavaScript بالإضافة للغات الويب HTML - CSS وتعمل أيضا على مختلف المنصات android - ios - web Xamarin تعمل بلغة #C .. وغيرهم، ما يهمك أول 3 من القائمة فهم الأكثر دعماً وفرص عمل. Flutter + React Native توفر شيفرة مصدرية أصلية لذلك أداء تطبيقاها أفضل.1 نقطة
-
1 نقطة
-
اريد موقع انترنت جاهز متكامل عن التسويق الالكتروني مع الشرح بالفديوهات من بداية التصميم حتئ رفعه ع الانترنت بلغة php وكم عيكون المبلغ المطلوب للموقع هذا1 نقطة
-
لايوجد سعر ثابت للمواقع، لوجود العديد من المتغيرات في طريقة حساب الكلفة، منها مكان إقامة المطور و خبرته وحجم المشروع إمكانية شراء إضافات أو توظيف مصمم وغيرها، وهذه عليك الاتفاق عليها مع المطور الذي سيعمل معك. يمكنك التوجه لموقعي خمسات ومستقل وإضافة مشروع، ثم التواصل مع المطورين هناك والتفاوض معهم لإنشاء الموقع.1 نقطة
-
1 نقطة
-
يخبرك في البداية أن كل دواء يتم بيعه بواسطة شركة دواء واحدة فقط ﻻ غير, نستنتج من هذا وجود عﻻقة one-to-many بين الدواء والشركة, والشركة في هذا الحالة هي الone والدواء هو الmany , ولكل جدول دواء يحمل خاصيتين, الأولى هي المعادلة والثانية هي العﻻمة التجارية, مع الأخذ بالإعتبار هنا أن العﻻمة التجارية حقل نادر ﻻ يمكن أن يتواجد لدى أكثر من تسجيل بالنسبة لجدول الشركة لها مفتاح أساسي(primary key) مكون من كلاً من الإسم ورقم الهاتف معاً بعد ذلك يخبرك أن لكل مريض طبيب واحد ولكل طبيب ع الأقل مريض مما يعني أن جدول المريض والطبيب بينهما عﻻقة one to many والواحد هو الطبيب, والكثير هو المريض المريض لديه مفتاح رئيسي وهو حقل الssn وله حقول أخرى الإسم والعنوان والسن الطبيب أيضا لديه في الجدول مفتاح رئيسي وهو الssn وحقول أخرى ليست رئيسية وهي الإسم والتخصص وعدد سنين البرة كل صيدلية تبيع عدد من الأدوية والدواء يمكن أن يباع في أي صيدلية, نفهم من هذه الجملة أن بين جدول الصيدلية وجدول الدواء عﻻقة many-to-many لكل صيدلية عنوان واسم ورقم هاتف وسعر الدواء حيث أن سعر الدواء يختلف من صيدلية لأخرى فسيتم وضعه إذا في الجدول المنفصل الذي سيربط الجدولين ببعض الطبيب من الممكن أن يقترح مجموعة عﻻج للمرضى ولكل مجموعة عﻻج تاريخ وكمية للدواء, مما يعني أن سيكون هناك عﻻقة بين جدول الطبيب وجدول الدواء وسيتم الربط بينهما في جدول خارجي شركة الأدوية من الممكن أن تتعاقد مع أكثر من صيدلية والصيدلية يمكنها التعاقد مع أكثر من شركة مما يعني وجود عﻻقة many-to-many ولكل عقد يتم تخزين تاريخ البدأ والإنتهاء ونص العقد, ويتم تخزين تلك المعلومات في جدول يربط بين الصيدلية والشركة1 نقطة
-
مرحبا عندي سؤال بعد اكمال أساسيات تطوير الويب ماذا افعل بعد ذلك هل اكمل تعلم بناء واجهة مستخدم تشبه موقع YouTube ام لا وشكرا1 نقطة
-
حاول التطبيق على الأشياء التي تعلمتها من الدورة أولاً, من المُفترض أن تكون قد طبقت وراء المُحاضر بناء موقع شخصي, حاول الأن أن تقوم بإنشاء موقع أخر , ستقابلك بعض المشاكل في محاولتك لإنشاء الموقع , إبحث عن المشاكل وحاول حلها بنفسك حتى تجني أكبر إستفادة ممكنة, إن لم تستطع حلها قم بسؤالنا وسنساعدك قدر المستطاع , وتأكد أنك فهمت أساسيات تطوير الويب بشكلٍ جيد إن كان هنالك شئُ غير واضح بالنسبة إليك قم بنشر سؤالك وسنحاول تبسيطه وتوضيحه ولكن ﻻ تدع شيئاً غير مفهوم او غير واضح بعد ذلك قم بإكمال تعلم بناء واجهة مستخدم تشبه موقع الyoutube مع مراعاة التطبيق وراء المُحاضر خطوة بخطوة والسؤال عن الأشياء الغير واضحة1 نقطة
-
مرحباً شوق ﻻ يجب أن يحل أحد تكليفاتك, بدلاً من ذلك حاول حلها بنفسك وأنشر سؤال عن الجزئية التي ﻻ تفهمها تحديدا او الجزئية التي يواجهك فيها صعوبة وتحتاج إلى توضيح1 نقطة
-
هناك اختلافات كثيرة بين http و https منها بالنسبة للأمان http : إنه أقل أمانًا حيث يمكن أن تكون البيانات عرضة للقراصنة. https :إنه مصمم لمنع المتسللين من الوصول إلى المعلومات الهامة لذا فهو آمن ضد مثل هذه الهجمات. بالنسبة للمنفذ http : يستخدم المنفذ 80 بشكل افتراضي https: يستخدم المنفذ 443 بشكل افتراضي. بالنسبة للرابط http :تبدأ عناوين HTTP URL بـ http:// https: تبدأ عناوين HTTPS URL بـ https: // بالنسبة للاستخدامات http : إنه مناسب تمامًا لمواقع الويب المصممة لاستهلاك المعلومات مثل المدونات. https : إذا احتاج موقع الويب إلى جمع المعلومات الخاصة مثل رقم بطاقة الائتمان فهو بروتوكول أكثر أمانًا. بالنسبة للتحقق من صحة اسم المجال http: موقع HTTP لا يحتاج إلى SSL. https : يتطلب HTTPS شهادة SSL. بالنسبة لترتيب البحث في محركات البحث http : لا يحسن HTTP تصنيفات البحث. https: يساعد HTTPS في تحسين ترتيب البحث. بالنسبة للسرعة http : سرعة عالية https: أقل سرعة من http1 نقطة
-
الHTTP(Hyper text transfer protocol) هو عبارة عن بروتوكول مُستخدم في نقل البيانات عبر الشبكة يتكون الHTTP من طلب ورد (request& response) ويكون جزأ الطلب مُقدم من المُستخدم (مثل المتصفح) , وجزأ الرد مُقدم من قِبل الخادم ,فمثلاً عند الضغط على زر تسجيل الدخول, يتم إرسال طلب(HTTP Request) إلى الخادم ويكون هذا الطلب حاملاً لبيانات التسجيل مثل البريد الإلكتروني وكلمة السر, ثم يرد الخادم بHTTP Response يحمل البيانات الﻻزمة التي يحتاجها المُستخدم للتعامل مع الموقع كأنه مُسجل يتم إرسال البيانات في الطلب والرد على هيئة نصوص غير مُشفرة, مما يعني أنه إذا إستطاع شخصٌ ما التصنت على الشبكة سيستطيع سرقة البيانات التي يتم تبادلها بين الخادم والمُستخدم, هنا يأتي دور الHTTPS حيث أنها هي هي الHTTP ولكن مَُضاف إليها طبقة حماية حيث تقوم بتشفير البياانات المُتبادلة بين الخادم والعميل لضمان عدم سرقتها في حالة التصنت عليها وبالنسبة لكلمة السر فﻻ يجب تشفيرها وقت تبادل البيانات في حالة إستخدام الHTTPS ولكن بالطبع يجب تشفيرها بواسطة دالة التجزئة(Hash function) قبل إدراجها في قاعدة البيانات1 نقطة
-
يمكن تحقيق ذلك عن طريق إنشاء محسِّنَيْن "GradientDescentOptimizer". لنفرض أن لديك شبكة مسبقة التدريب من 5 طبقات ونريد ضبط معدل التعلم لأول لهم على 0.00001 ونريد طبقة إضافية بمعدل 0.0001 . في هذه الحالة يمكنك استخدام tf.trainable_variables للحصول على جميع متغيرات التدريب وتقرر الاختيار من بينها. كالتالي: var_list1 = [variables from first 5 layers] var_list2 = [the rest of variables] opt1 = tf.train.GradientDescentOptimizer(0.00001) opt2 = tf.train.GradientDescentOptimizer(0.0001) grads = tf.gradients(loss, var_list1 + var_list2) grads1 = grads[:len(var_list1)] grads2 = grads[len(var_list1):] tran_op1 = opt1.apply_gradients(zip(grads1, var_list1)) train_op2 = opt2.apply_gradients(zip(grads2, var_list2)) train_op = tf.group(train_op1, train_op2)1 نقطة
-
طالما أنك لم تعطنا مصدر البيانات فلايمكننا تحديد المشكلة، لكن هناك احتمالين الأول هو أنه هناك مسافات فارغة (وحلها كما أشار أيضاً)، أو أن هناك separator مختلف فافتراضياً يكون الفاصل هو "," لكن ليس بالضرورة دوماً لذا يجب عليك: إذا كنت تعرف نوع ال separator فقم بتعيينه مباشرة للوسيط. أو إذا لم تكن تعرفه قم بفتح ملف ال csv وتحقق من نوع ال separator. على سبيل المثال إذا كان ; نقوم بقراءة البيانات بالشكل: pd.read_csv("D:\\data.csv", sep=';')1 نقطة
-
يمكنك القيام بذلك من خلال التابع التالي: //importAll تعريف تابع function importAll(r) { let images = {}; r.keys().map((item, index) => { images[item.replace('./', '')] = r(item); }); return images; } // استخدامه const images = importAll(require.context('./images', false, /\.(png|jpe?g|svg)$/)); <img src={images['doggy.png']} />1 نقطة
-
ألكود التالي هو كل ماتحتاج إليه وذلك من أجل كل الأنظمة : const process = require('process'); //platform من خلال الواصفة var platform = process.platform; switch(platform) { case 'aix': // هنا تقوم بماتريد console.log("IBM AIX platform"); break; case 'darwin': // هنا تقوم بماتريد console.log("Darwin platform(MacOS, IOS etc)"); break; case 'freebsd': // هنا تقوم بماتريد console.log("FreeBSD Platform"); break; case 'linux': // هنا تقوم بماتريد console.log("Linux Platform"); break; case 'openbsd': // هنا تقوم بماتريد console.log("OpenBSD platform"); break; case 'sunos': // هنا تقوم بماتريد console.log("SunOS platform"); break; case 'win32': // هنا تقوم بماتريد console.log("windows platform"); break; default: const os = require('os'); var type = os.type(); switch(type) { //Windows_NT حالة النظام كان case 'Windows_NT': // هنا تقوم بماتريد console.log("windows operating system"); break; }1 نقطة
-
من خلال emitter.setMaxListeners(n) بحيث n هي عدد صحيح ويعيد <EventEmitter> وبشكل افتراضي ، سيقوم EventEmitters بطباعة تحذير إذا تمت إضافة أكثر من 10 مستمعين "listeners" لحدث معين. لكن تسمح الدالة emitter.setMaxListeners بتعديل ذلك حيث يمكنك ضبطه على Infinity (أو 0) للإشارة إلى عدد غير محدود من المستمعين. مثال: const emitter = new EventEmitter() emitter.setMaxListeners(100) //limit أو 0 لإيقاف ال emitter.setMaxListeners(0) يتم ضبطه على 10 بشكل افتراضي لأن هذا يساعد في تجنب الوصول إلى حالة Memory leak" تسرب الذاكرة" (الاستهلاك غير المتعمد للذاكرة المؤقتة "ram" في الحاسوب، بواسطة برنامج حاسوب، حيث يفشل البرنامج في إفراغ الذاكرة بعد الانتهاء من استخدامه).1 نقطة
-
يمكنك تحويل إطار البيانات بالكامل إلى سلسلة ثم عرضه من خلال الدالة display: import numpy as np from sklearn.datasets import load_iris import pandas as pd data = load_iris() df = pd.DataFrame(data.data, columns = data.feature_names) display(df.to_string()) أو من خلال pd.option_context: import numpy as np from sklearn.datasets import load_iris import pandas as pd data = load_iris() df = pd.DataFrame(data.data, columns = data.feature_names) with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.precision', 3, ): print(df) كذلك يمكنك استخدام pd.set_option، ثم عرضها من خلال display: import numpy as np from sklearn.datasets import load_iris import pandas as pd data = load_iris() df = pd.DataFrame(data.data, columns = data.feature_names) # لعرض أكبر عدد من الأسطر و الأعمدة نقوم بعمليات الضبط التالية pd.set_option('display.max_rows', None) pd.set_option('display.max_columns', None) pd.set_option('display.width', None) pd.set_option('display.max_colwidth', -1) # قبل display(df) print('**RESET_OPTIONS**') # تطبيق المحددات السابقة pd.reset_option('all') # الآن سيتم عرضها بالكامل display(df)1 نقطة
-
سأقوم بإنشاء قالب للقيام بذلك: import numpy as np import tensorflow.train.string_input_producer as qu import tensorflow.train.start_queue_runners as sqr import tensorflow as tf # قائمة بالملفات التي سنقرأها queue = qu(['tf.png']) # قراءة الملفات _, v = tf.WholeFileReader().read(queue) #حسب نوع الصور التي لديك decode_jpeg أو decode_png استخدم image = tf.image.decode_png(v) initialize = tf.initialize_all_variables() with tf.Session() as sess: sess.run(initialize) # ملء قائمة انتظار اسم الملف c = tf.train.Coordinator() threads = sqr(coord=c) for i in range(1): # طول القائمة التي لدينا image = image.eval() # الصورة ك تنسر # طباعة أبعادها image.shape # عرضها Image.show(Image.fromarray(np.asarray(image))) coord.request_stop() coord.join(threads) الكود السابق يقوم فقط بتحميل الصورة كتنسر والآن لحفظها ضمن ملف TFRecords: def _int64_feature(value): return tf.train.Feature(int64_list=tf.train.Int64List(value=[value])) def _bytes_feature(value): return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) # مجموعة الصور والتسميات كمدخلات def convert_to(images, labels, name): num_examples = labels.shape[0] if images.shape[0] != num_examples: raise ValueError("Images size %d does not match label size %d." % (images.shape[0], num_examples)) rows = images.shape[1] cols = images.shape[2] depth = images.shape[3] filename = os.path.join(FLAGS.directory, name + '.tfrecords') print('Writing', filename) writer = tf.python_io.TFRecordWriter(filename) for index in range(num_examples): image_raw = images[index].tostring() example = tf.train.Example(features=tf.train.Features(feature={ 'height': _int64_feature(rows), 'width': _int64_feature(cols), 'depth': _int64_feature(depth), 'label': _int64_feature(int(labels[index])), 'image_raw': _bytes_feature(image_raw)})) writer.write(example.SerializeToString()) ثم لقراءتها لاحقاً: #"train.TFRecord" لاتنسى إنشاء قائمة انتظار لاسم الملف لمسار ملف # القيمة المعادة لهذا التابع هو بياناتك بعد قراءتها #label أي الصورة وال def read_and_decode(filename_queue): reader = tf.TFRecordReader() _, serialized_example = reader.read(filename_queue) features = tf.parse_single_example( serialized_example, dense_keys=['image_raw', 'label'], # لم يتم تحديد الإعدادات الافتراضية لأن كلا المفتاحين مطلوبان dense_types=[tf.string, tf.int64]) image = tf.decode_raw(features['image_raw'], tf.uint8) image = tf.reshape(image, [my_cifar.n_input]) image.set_shape([my_cifar.n_input]) # إذا أردت يمكنك هنا أن تقوم بإعادة تعيين أبعاد الصور لديك أو تطبيق بعض العمليات على الصورة # الآن سنقوم بتحويل الصورة لفكتور # Convert from [0, 255] -> [-0.5, 0.5] floats. image = tf.cast(image, tf.float32) image = tf.cast(image, tf.float32) * (1. / 255) - 0.5 #int32 إلى uint8 التحويل من label = tf.cast(features['label'], tf.int32) return image, label1 نقطة
-
إليك نسخة مبسطة من إجابة سامح باستخدام نموذج فارغ كقالب: <h3>My Services</h3> {{ serviceFormset.management_form }} <div id="form_set"> {% for form in serviceFormset.forms %} <table class='no_error'> {{ form.as_table }} </table> {% endfor %} </div> <input type="button" value="Add More" id="add_more"> <div id="empty_form" style="display:none"> <table class='no_error'> {{ serviceFormset.empty_form.as_table }} </table> </div> <script> $('#add_more').click(function() { var form_idx = $('#id_form-TOTAL_FORMS').val(); $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx)); $('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1); }); </script>1 نقطة
-
بفرض لدي التنسر التالية: ten = tf.constant([[0.0, 0.0], [0.0, 0.0]]) #[0,0] ونريد تعديل الخلية idx = [[0, 0]] # قائمة بالمواقع المراد تحديث قيمها # القيمة المراد إضافتها val = [3.0] # أبعاد المصفوفة dim = [2, 2] k = tf.SparseTensor(idx, val, dim) ثم نستخدم العملية tf.sparse_tensor_to_dense لإنشاء dense tenso من k ثم إضافتها ل ten: out = ten + tf.sparse_tensor_to_dense(k) sess = tf.Session() sess.run(out) # ==> array([[ 3., 0.], # [ 0., 0.]], dtype=float32)1 نقطة
-
على كل يمكنك إعادة العملية من جديد و التأكد من سلامة كل خطوة . 1 - قومي بإنشاء مستودع جديد على الGITHUB . 2 - فتح الـ CMD على روت البروجكت و طباعة الأمور : git init ثم إضافة كل البروجكت: git add -A ثم : git commit -m "initial commit" ثم إنشاء Branch : git branch -M main ثم : git remote add origin https://github.com/github-username/repo-name.git ثم أخيرا : git push -u origin main .. في حالة ظهور أي خطأ في أي مرحلة من المراحل السابقة يجب الإشارة إليها و للخطأ . تحديث : قد تحتاجين عمل undo ﻷي git init سابق قبل إعادة العملية من جديد , يمكنك ذلك عن طريق طباعة الأمر : rm -rf .git1 نقطة
-
يعتبر React.js -على حداثته- من أقوى أطر عمل Javascript (بعضهم قد يسميه مكتبة وليس إطار عمل) لبناء الواجهات الرسومية على الويب، حيث طبّق أفكارًا جديدة في هذا المجال، جعلت شِفرة الواجهات البرمجية أكثر نظافة، سرعة وأكثر قابلية للصيانة. يسمح لك React ببناء الواجهة الرسومية في مجموعة مكونات، كل مكوّن عبارة عن سرد لهيكلة ومنطق المكون، إذا تمزج بين شِفرة HTML مخصصّة وشِفرة جافاسكربت تصف سلوك ذاك المكون، ليكون قائما بذاته وقابلا لإعادة الاستعمال. إطار عمل React مُطور من طرف شركة فيس بوك (Facebook)، وقد يكفيك ثقة ويجذب انتباهك بمجرد أن تعرف أن فيس بوك نفسها تستخدم React في واجهتها البرمجية على موقع Facebook نفسه! يمكنك فتح موقع Facebook وعرض شفرة HTML الخاصة به والبحث عن كلمة react للتأكد بنفسك. سنقوم في هذا الدرس بإنشاء مُربَّع تعليقات بسيط وفعَّال بإمكانك وضعه في مدوَّنتك، سيكون المُربَّع عبارة عن نُسخة مُجرَّدة من التعليقات الآنية التي تُقدمها لك تعليقات Disquse ،LiveFyre أو فيس بوك. ستجد في نهاية الدَّرس أنَّ لديكَ مُربَّع تعليقات يوفِّر ما يلي: عرض لجميع التعليقات.نموذج لإرسال تعليق.خُطَّافات لتوفير مُنتهى خلفي مُخصَّص custom backend.سوف يحتوي مُربَّع التعليقات كذلك على بعض المزايا اللَّطيفة: تعليق مُحسَّن: تظهر التَّعليقات في القائمة قبل أن يتمّ حفظها على الخادم وبناءً عليه تظهر التَّعليقات في التوِّ واللَّحظة.تحديثات حيَّة: تظهر تعليقات المستخدمين الآخرين في عرض التَّعليقات في نفس وقت الإرسال.هيئة Markdown: يُمكن للمستخدمين استخدام Markdown لتهيئة نصوصهم.هل ترغب في تخطِّي كل هذا ومعاينة المصدر؟ كل شيء موجود على GitHub. تشغيل الخادمرغم أنَّه ليس من الضروري أن تبدأ بهذا الجزء من الدرس إلَّا أنَّنا سنقوم في وقت لاحق بإضافة وظائف تتطلَّب المُشاركة POST إلى خادم قيد التشغيل. إذا كُنتَ واثقٌ من أنّك على دراية بهذا الأمر وترغب في إنشاء خادمك الخاص يُمكنكَ القيام بذلك. ولِمَن يُريد التَّركيز على تعلُّم React دون الحاجة إلى القلق بشأن جوانب الخادم، فلقد كتبنا خوادم بسيطة بعددٍ من اللُّغات: Python ،Ruby ،Go، Node.js و PHP. كلُّ هذا مُتاح على GitHub. يُمكن الاطِّلاع على المصدر أو تحميل ملفّ مضغوط للبدء. للبدء بتطبيق هذا الدَّرس، كلّ ما عليكَ فعله هو بداية تحرير public/index.php. البدءسنستخدم لهذا الدرس ملفَّات JavaScript سبق إنشاؤها على شبكة توصيل مُحتوى CDN. قم بفتح المُحرِّر المفضَّل لديك وقم بإنشاء مُستند HTML جديد: <!-- index.html --> <!DOCTYPE html> <html> <head> <title>Hello React</title> <script src="https://fb.me/react-0.13.3.js"></script> <script src="https://fb.me/JSXTransformer-0.13.3.js"></script> <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script> </head> <body> <div id="content"></div> <script type="text/jsx"> // Your code here </script> </body> </html>سيتمّ كتابة شفرات JavaScript في وسم السكربت هذا طوال الفترة المتبقية من الدرس. مُلاحظة: قُمنا بإدراج jQuery هُنا لأننا نٌريد تبسيط الشَّفرات لاستدعاءات Ajax في المُستقبل، ولكنَّها ليست إلزاميَّة لعمل React. مُكوِّنكَ الأوَّلتتمحور الفكرة الأساسيَّة لـ React حول كل شيءٍ له علاقة بالمُكوِّنات التركيبيَّة القابلة للتَّشكيل modular, composable components. سنستخدم بنية المُكوٍّنات التالية لمثال مُربَّع التَّعليقات لهذا الدرس: - CommentBox - CommentList - Comment - CommentFormسنقوم الآن ببناء المُكوِّن CommentBox وما هو إلَّا وسم بسيط: // tutorial1.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> Hello, world! I am a CommentBox. </div> ); } }); React.render( <CommentBox />, document.getElementById('content') );لاحظ أن أسماء عناصر HTML تبدأ بحرف صغير في حين أن أسماء فئات React تبدأ بحرف كبير. 1. صياغة JSXستُلاحظ أوَّل ما تلاحظ تلكَ الصياغة المُشابهة لـ XML في شفرة JavaScript. لدينا precompiler بسيط يُترجم الجُملة البسيطة Syntactic Sugar إلى شفرات JavaScript المُجرَّدة هذه: // tutorial1-raw.js var CommentBox = React.createClass({displayName: 'CommentBox', render: function() { return ( React.createElement('div', {className: "commentBox"}, "Hello, world! I am a CommentBox." ) ); } }); React.render( React.createElement(CommentBox, null), document.getElementById('content') );إنَّ استخدام صياغة JSX اختياري ولكن وجدنا أنَّها أسهل استخدامًا من شفرات JavaScript مُجرَّدة. يُمكن قراءة المزيد في مقال صياغة JSX 2. ماذا يحدث هنانقوم بتمرير بعض الوظائف في كائن JavaScript إلى دالَّة ()React.createClass لإنشاء مُكوِّن React جديد. أهم هذه الوظائف ما تُسمَّى تصيير render والتي تُعيد شجرة من مُكوِّنات React والتي في نهاية المطاف ستقوم بالتصيير عبر HTML. لا تُعتبر وسوم عُقَد نموذج كائن مُستند DOM فعليَّة، وإنَّما هي تمثيلات من مُكوِّنات div الخاصَّة بـ React. يُمكنكَ اعتبارها كوسوم أو قطع من البيانات والتي يعرف React كيفيَّة التعامل معها. React آمن. لا نقوم بتوليد سلاسل HTML لذلك فإن حماية XSS تُعتبر الافتراضيَّة. لا يجب عليكَ إعادة شفرات HTML قياسيَّة. وإنَّما يُمكنكَ إعادة شجرة من المُكوِّنات التي قُمتَ (أو شخص آخر قام) ببنائها. هذا ما يجعل React قابلة للتَّشكيل composable: وهي عقيدة أساسيَّة في الواجهات الأماميَّة القابلة للصّيانة. يقوم ()React.render بتمثيل المُكوِّن القاعدي، بدء عمل الإطار، ثم إدخال الوسوم إلى عنصر نموذج كائن مُستند خام، يتمّ تقديم تلك الوسوم كمُعطى ثاني . تركيب المُكوِّناتسنُنشيء الآن هياكل بناء لكلٍّ من المُكوِّنين CommentList وCommentForm والتي ستكون -مرَّة أخرى- عبارة عن وسوم بسيطة. أضِف هذين المُكوِّنين إلى ملفِّك مع الحفاظ على تعريف commentBox الحالي واستدعاء React.render: // tutorial2.js var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> Hello, world! I am a CommentList. </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } });ما سنقوم بعمله الآن هو تحديث مُكوِّن CommentBox لاستخدام المُكوِّنات الجديدة: // tutorial3.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList /> <CommentForm /> </div> ); } });لاحظ كيف تمَّ مزج وسوم HTML والمُكوِّنات التي قُمنا ببنائها. إنَّ مُكوِّنات HTML ما هي إلَّا مُكوِّنات React مُنتظمة، تمامًا مثل تلك التي تقوم بتعريفها ولكن مع فارق واحد. سيقوم مترجم JSX تلقائيًا بإعادة كتابة وسوم HTML إلى تعبيرات React.createElement() tagName وترك كل شيء على حدة. وهذا لمنع حدوث التَّلوّث في مساحة الاسم العموميَّة global namespace. استخدام الخصائصسنقوم الآن بانشاء مُكوِّن Comment، والذي سوف يعتمد على البيانات التي تمَّ تمريرها إليه من المُكوِّن الأساسي. يتمّ اتاحة البيانات التي تمّ تمريرها من مُكوِّن أساسي كـ "خاصيَّة" في المُكوِّن الفرعي. ويتمّ الوصول إلى هذه "الخصائص" من خلال this.props. يُمكننا باستخدام الخصائص props قراءة البيانات التي تمّ تمريرها إلى Comment من CommentList، وتصيير بعض الترميزات: // tutorial4.js var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {this.props.children} </div> ); } });يُمكنكَ وضع نصّ أو مُكوِّنات React في الشَّجرة وذلك بإحاطة تعبير JavaScript بأقواس داخل JSX (إما كخاصيَّة أو كمُكوِّن فرعي). نقوم بالوصول إلى خاصيَّات مُسمَّاه تمّ تمريرها إلى عنصر كمفاتيح على this.props وأيّ عناصر مُتداخلة كما this.props.children. خصائص المُكوِّننحتاج الآن وبعد أن قمنا بتحديد مُكوِّن Comment إلى تمرير اسم الكاتب ونصّ التعليق إلى هذا المُكوِّن. يسمح لنا هذا بإعادة استخدام نفس الشَّفرة لكلِّ تعليق مُختلف. لنقوم الآن بإضافة بعض التَّعليقات داخل مُكوِّن CommentList: // tutorial5.js var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> <Comment author="Pete Hunt">This is one comment</Comment> <Comment author="Jordan Walke">This is *another* comment</Comment> </div> ); } });لاحظ أنَّنا قد قُمنا بتمرير بعض البيانات من مُكوِّن CommentList الأساسي إلى مُكوِّنات Comment الفرعيَّة. مرَّرنا على سبيل المثال Pete Hunt (عن طريق خاصيَّة) وThis is one comment (عن طريق عُقدة فرعيَّة تُشبه XML) إلى Comment الأوَّل. وكما ذكرنا بالأعلى فإنَّ مُكوِّن Comment سيعمل على الوصول إلى هذه الخصائص من خلال this.props.author، وthis.props.children. إضافة MarkdownMarkdown هي طريقة بسيطة لتهيئة مُضمّنة inline لنصِّك. على سبيل المثال، احاطة النص بعلامة النجمة (*) سيقوم بتأكيده. أولًا، أضِف مكتبة الطرف الثالث marked إلى تطبيقك. Marked هي مكتبة JavaScript تقوم بأخذ نص Markdown وتُحوِّله إلى صيغة HTML خام. هذا الأمر يتطلَّب وسم سكربت في قسم head (قُمنا بادراجه بالفعل في أرضيَّة React): <!-- index.html --> <head> <title>Hello React</title> <script src="https://fb.me/react-0.13.3.js"></script> <script src="https://fb.me/JSXTransformer-0.13.3.js"></script> <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script> </head>سنقوم بعد ذلك بتحويل نصّ التَّعليق إلى Markdown ومن ثمَّ إخراجه: // tutorial6.js var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {marked(this.props.children.toString())} </div> ); } });كل ما فعلناه هنا هو استدعاء مكتبة marked. نحتاج إلى تحويل this.props.children من نصّ React مُحاط إلى سلسلة خام يُمكن لمكتبة marked فهمها ولذلك فإننا نقوم بستدعاء دالَّة ()toString. لكن لدينا مشكلة وهي أنَّه يتمّ إظهار وسوم HTML الموجودة في التَّعليقات بالشكل التَّالي في المُتصفح: This is another comment. هذا الأمر هو حماية React لك من هجوم XSS. هُناك طريقة للالتفاف على ذلك، ولكنَّ إطار العمل يُحذِّرُكَ من استخدامها: // tutorial7.js var Comment = React.createClass({ render: function() { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } });هذه الشَّفرات هي API خاصّ والذي عمدًا يجعل من الصَّعب إدراج شفرات HTML خام، في حالتنا بالنِّسبة لمكتبة marked فإنَّنا سنقوم بالاستفادة من هذا المنفذ الخلفيّ. تذكَّر: باستخدامك لهذه الميزة فإنَّك تعتمد على مكتبة marked أن تكون آمنة. نقوم في هذه الحالة بتمرير sanitize: true التي تطلب من مكتبة marked تنفيذ أي وسم HTML في المصدر بدلًا من تمريره دون تغيير. إضافة نموذج البياناتحتَّى الآن فإنَّنا نقوم بإدراج تعليقات مُباشرة في شفرات المصدر. بدلًا من ذلك، سنقوم بتصيير بضع من بيانات JSON في قائمة التعليق. يأتي هذا من الخادم في نهاية المطاف، ولكن في الوقت الراهن سنكتبها نحن في المصدر: // tutorial8.js var data = [ {author: "Pete Hunt", text: "This is one comment"}, {author: "Jordan Walke", text: "This is *another* comment"} ];الآن نحنُ بحاجة إلى إدخال هذه البيانات في مُكوِّن CommentList بطريقة نموذجيِّة. قُم بتعديل CommentBox واستدعاء ()React.render لتمرير هذه البيانات إلى CommentList عن طريق الخصائص props: // tutorial9.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.props.data} /> <CommentForm /> </div> ); } }); React.render( <CommentBox data={data} />, document.getElementById('content') );الآن حيثُ أنَّ البيانات مُتاحة في CommentList، سوف نقوم بتقديم التَّعليقات بطريقة ديناميكيَّة: // tutorial10.js var CommentList = React.createClass({ render: function() { var commentNodes = this.props.data.map(function (comment) { return ( <Comment author={comment.author}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } });هذا كل شيء. الاستدعاء من الخادمسنعمل الآن على استبدال البيانات الثَّابتة ببعض البيانات الديناميكيَّة من الخادم. يتمّ ذلك بإزالة خاصيَّة البيانات data prop واستبدالها بعنوان URL للجلب: // tutorial11.js React.render( <CommentBox url="comments.json" />, document.getElementById('content') );هذا المُكوِّن مُختلف عن المُكوِّنات السَّابقة حيثُ أنَّه سيضطر إلى إعادة تصيير نفسه. لن يحتوي المُكوِّن على أيّ بيانات إلى أن يعود الطَّلب من الخادم، في هذه الحالة قد يحتاج المُكوِّن إلى تصيير بعض التَّعليقات الجديدة. الحالة التفاعليَّةقام كلّ مُكوِّن حتَّى الآن على أساس خصائصه بتصيير نفسه مرة واحدة. الخصائص props ثابتة: يتمّ تمريرها من المُكوِّن الأساسي و”مملوكة” من قبل المُكوِّن الأساسي كذلك. لتنفيذ التَّفاعلات، فإنَّنا نُقدِّم حالة قابلة للتغيير إلى المُكوِّن. حالة this.state هي خاصَّة بالمُكوِّن ويُمكن تغييرها من خلال استدعاء ()this.setState يقوم المُكوِّن بإعادة تقديم نفسه عند تحديث الحالة. وظائف ()render مكتوبة إلزاميًّا كدوال this.props وthis.state. يضمن إطار العمل أن تكون واجهة المستخدم دائمًا مُتَّسِقَة مع المُدخَلات. عندما يقوم الخادم بجلب بيانات سنقوم نحن بتغيير بيانات التعليق لدينا. لنُضيف الآن مصفوفة من بيانات التَّعليق كحالة للمُكوِّن CommentBox: // tutorial12.js var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } });يتمّ تنفيذ دالَّة ()getInitialState مرَّة واحدة فقط خلال دورة حياة المُكوِّن كما أنَّها تبدأ الحالة الأوليَّة للمُكوِّن. تحديث الحالةنُريد عند إنشاء المُكوِّن لأوَّل مرَّة أن نحصل على (GET) بعض بيانات JSON من الخادم وتحديث الحالة لتعكس أحدث البيانات. هذا من شأنه أن يكون نقطة نهاية ديناميكيَّة لو كان الأمر في تطبيق حقيقي، ولكن سنستخدم لهذا المثال ملف JSON ثابت لابقاء الأمور بسيطة: // tutorial13.json [ {"author": "Pete Hunt", "text": "This is one comment"}, {"author": "Jordan Walke", "text": "This is *another* comment"} ]سنقوم باستخدام مكتبة jQuery للمساعدة في عمل طلب غير متزامن asynchronous request إلى الخادم. مُلاحظة: حيثُ أنَّ هذا الأمر أصبح تطبيق AJAX فإنَّك سوف تحتاج لتطوير تطيبقك باستخدام خادم ويب بدلًا من أن ملف موجود في نظام ملفاتك. قدَّمنا -كما هو مذكورٌ بالأعلى- العديد من الخوادم التي يُمكنكَ استخدامها على GitHub. توفر تلك الخوادم التأدية الوظيفيَّة التي تحتاجها لبقيَّة هذا الدرس. // tutorial13.js var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, componentDidMount: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } });وظيفة componentDidMount هنا هي وظيفة تُستدعى تلقائيًا بواسطة React عندما يتمّ تصيير مُكوِّن. مفتاح التَّحديثات الديناميكيَّة هو استدعاء دالَّة ()this.setState. نقوم باستبدال مصفوفة التَّعليقات القديمة بواحدة جديدة من الخادم وتقوم واجهة المستخدم بتحديث نفسها تلقائيًا. بسبب هذا التفاعل، يُعتبر التغيير لإضافة تحديثات حيَّة طفيفًا. سوف نستخدم أسلوب بسيط في هذا الدَّرس ولكن لكَ الحُريَّة في استخدام WebSockets أو غيرها من التكنولوجيَّات. // tutorial14.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } }); React.render( <CommentBox url="comments.json" pollInterval={2000} />, document.getElementById('content') );كل ما فعلناه هنا هو نقل استدعاء AJAX إلى وظيفة مُستقلَّة واستدعائها عند تحميل المُكوِّن الأوَّل واستدعائها كلّ ثانيتين بعد ذلك. حاول تشغيل هذا في مُتصفِّحك وتغيير ملف comments.json. في غضون ثانيتين ستظهر لكَ التغييرات. إضافة تعليقات جديدةحان الآن الوقت لبناء النموذج. على مُكوِّن CommentForm أن يسأل المُستخدم عن اسمه ونصّ التَّعليق، ثم يقوم بإرسال طلب إلى الخادم لحفظ التعليق. // tutorial15.js var CommentForm = React.createClass({ render: function() { return ( <form className="commentForm"> <input type="text" placeholder="Your name" /> <input type="text" placeholder="Say something..." /> <input type="submit" value="Post" /> </form> ); } });دعونا نجعل النموذج متجاوب. عندما يقوم المُستخدم بإرسال النَّموذج، يجب علينا مسحه clear، تقديم طلب إلى الخادم، ثُمَّ تحديث قائمة التعليقات. للبدء في تنفيذ هذا، سقوم بالاستماع إلى حدث ارسال النَّموذج ومسحه. // tutorial16.js var CommentForm = React.createClass({ handleSubmit: function(e) { e.preventDefault(); var author = React.findDOMNode(this.refs.author).value.trim(); var text = React.findDOMNode(this.refs.text).value.trim(); if (!text || !author) { return; } // TODO: send request to the server React.findDOMNode(this.refs.author).value = ''; React.findDOMNode(this.refs.text).value = ''; return; }, render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" ref="author" /> <input type="text" placeholder="Say something..." ref="text" /> <input type="submit" value="Post" /> </form> ); } });1- الأحداث Eventsتقوم React بإرفاق مُعالجات الحدث في المُكوِّنات باستخدام اتفاقية التَّسمية camelCase. نقوم بإرفاق مُعالج onSubmit إلى النَّموذج الذي يعمل على مسح حقول النَّموذج عند إرساله مع إدخال صحيح. عليكَ استدعاء ()preventDefault بالحدث لمنع الإجراء الافتراضي للمُتصفِّح من اعتماد النَّموذج. 2- المراجع Refsنستخدم خاصيَّة ref لتعيين اسم للمُكوِّن الفرعي وthis.refs لارجاع المُكوِّن. يمكن أن نستدعي (React.findDOMNode(componentعلى مُكوّن للحصول على عنصر نموذج كائن مُستند المُتصفِّح الأصلي. 3- نداءات الخصائصعندما يُرسِل المُستخدم التَّعليق، فإنَّنا سوف تحتاج إلى تحديث قائمة التَّعليقات لتشمل التَّعليق الجديد. من الطبيعي أن تفعل كل هذا في مُكوِّن CommentBox حيث أنَّ المُكوِّن يمتلك الحالة التي تُمثِّل قائمة التَّعليقات. نحن بحاجة لتمرير البيانات من نُسخة المُكوِّن الفرعي الاحتياطيَّة إلى المُكوِّن. يتمّ فعل هذا في وظيفة render الخاصَّة بالأب عن طريق تمرير رد نداء جديد (handleCommentSubmit) في الابن ثُمَّ الزامها لحدث الابن onCommentSubmit. كُلَّما تم تشغيل الحدث، سيُنفَّذ الاستدعاء: // tutorial17.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { // TODO: submit to the server and refresh the list }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });سوف نستدعي الآن النِّداء من CommentForm عندما يقوم المُستخدم بإرسال النَّموذج: // tutorial18.js var CommentForm = React.createClass({ handleSubmit: function(e) { e.preventDefault(); var author = React.findDOMNode(this.refs.author).value.trim(); var text = React.findDOMNode(this.refs.text).value.trim(); if (!text || !author) { return; } this.props.onCommentSubmit({author: author, text: text}); React.findDOMNode(this.refs.author).value = ''; React.findDOMNode(this.refs.text).value = ''; return; }, render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" ref="author" /> <input type="text" placeholder="Say something..." ref="text" /> <input type="submit" value="Post" /> </form> ); } });الآن وبعد أن أصبح النِّداء في مكانه الصحيح، كل ما علينا القيام به هو الإرسال إلى الخادم وتحديث القائمة: // tutorial19.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });تحديثات مُحسَّنةمشروعنا الآن كامل الوظائف ولكن من المُمل أن نقوم بانتظار الطَّلب حتَّى يكتمل قبل ظهور تعليقك في القائمة. يُمكننا إضافة هذا التَّعليق إلى القائمة لجعل التطبيق يعمل بشكلٍ أسرع. // tutorial20.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { var comments = this.state.data; var newComments = comments.concat([comment]); this.setState({data: newComments}); $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });ختامًاانتهيتَ لتوك من إنشاء مربع تعليقات في بضع خطوات بسيطة. يُمكنك الآن التَّعرُّف على المزيد حول أسباب استخدام React، أو الخوض في مراجع API وبدء العمل. ترجمة -وبتصرّف- للمقال: Tutorial | React.1 نقطة