كيفية إنشاء تطبيق اختبار باستخدام React - with Tips and Starter Code

في هذا البرنامج التعليمي للمبتدئين من React ، سننشئ تطبيق اختبار. سنعمل مع كائنات الحالة المعقدة ، وكيفية التعامل مع خطاطيف الحالة المختلفة ، وتقديم الأشياء بناءً على الحالة.

تحقق من ذلك:

جربها بنفسك

إذا كنت تريد أن تبدأ بنفسك أولاً ، فإليك السيناريوهات (يمكنك أيضًا الحصول على رمز البدء أدناه):

  • عندما ينقر المستخدم على زر ، يجب أن يظهر السؤال التالي
  • إذا حصل المستخدم على السؤال بشكل صحيح ، فيجب عليه زيادة درجاته
  • عندما يصل المستخدم إلى نهاية الاختبار ، يجب إظهار مجموع درجاته

فيديو تجول

كود المبتدئين

احصل عليه في GitHub هنا.

لنذهب!

إذا فتحت رمز البدء وانتقلت إلى App.js ، فسترى أنني قدمت لك قائمة بالأسئلة / الإجابات ، مخزنة كمصفوفة تسمى الأسئلة . هذا هو اختبارنا.

هدفنا الأول هو أخذ بيانات السؤال من المصفوفة وعرضها على الشاشة.

سنقوم بإزالة النص الثابت ونأخذ البيانات من السؤال الأول في الوقت الحالي ، فقط لنبدأ الأمور. سنقلق بشأن تبديل الأسئلة لاحقًا.

في JSX الخاص بنا ، أزل نص السؤال المشفر واكتب {questions[0]}للحصول على العنصر الأول (أو السؤال) في مصفوفة الأسئلة لدينا.

 {questions[0]} 

تقديم السؤال والأجوبة

السؤال الأول هو كائن ، لذا يمكننا استخدام "تدوين النقطة" للوصول إلى الخصائص. الآن سنفعل فقط {question[0].questionText}للوصول إلى نص السؤال لهذا الكائن:

 {questions[0].questionText} 

احفظ التطبيق وقم بتشغيله. لاحظ كيف يتم تحديث النص. تذكر أننا أخذنا نص السؤال الأول من العنصر الأول في مصفوفة الأسئلة.

سنتخذ نهجًا مشابهًا لخيارات الإجابة. قم بإزالة الأزرار المشفرة وسنستخدم وظيفة الخريطة للتكرار فوق خيارات الإجابة لسؤال معين.

تذكر أن وظيفة الخريطة تدور فوق المصفوفة وتعطينا العنصر الحالي الذي توجد فيه الحلقة حاليًا ، في شكل متغير.

استبدل قسم "قسم الإجابات" بما يلي:

 {questions[0].answerOptions.map((answerOption, index) => ( {answerOption.answerText} ))} 

احفظ التطبيق وقم بتشغيله. لاحظ كيف تظهر أربعة أزرار للإجابة ويتم عرض النص ديناميكيًا.

دعونا نلخص:

  • نحصل على السؤال الأول من مجموعة الأسئلة: questions[0]
  • السؤال الأول هو كائن يحتوي على مصفوفة من answerOptions. يمكننا الوصول إلى هذه المصفوفة باستخدام تدوين النقطة:questions[0].answerOptions
  • نظرًا لأن answerOptionsالمصفوفة عبارة عن مصفوفة ، فيمكننا تعيين ما يلي:questions[0].answerOptions.map
  • داخل وظيفة الخريطة ، نعرض زرًا لكل منها answerOption، ونعرض النص

تغيير الأسئلة باستخدام الدولة

لنعد الآن إلى JSX. لاحظ كيف إذا قمنا بالتغيير questions[0]إلى questions[1]، أو questions[2]سيتم تحديث واجهة المستخدم. هذا لأنه يأخذ البيانات من أسئلة مختلفة في مصفوفة الأسئلة لدينا ، اعتمادًا على الفهرس.

ما نريد القيام به هو استخدام كائن الحالة للاحتفاظ بالسؤال الذي يعمل عليه المستخدم حاليًا ، وتحديث هذا عند النقر فوق زر الإجابة. يمكنك أن ترى هذا من تشغيل الكود في المثال الأخير.

انطلق وأضف كائن الحالة ، والذي سيحتوي على رقم السؤال الحالي الذي يعمل عليه المستخدم. سيتم تهيئته إلى 0 بحيث يأخذ الاختبار السؤال الأول من المصفوفة:

const [currentQuestion, setCurrentQuestion] = useState(0); 

الآن نريد استبدال "0" المشفر في JSX بهذا المتغير. أولاً لنص السؤال:

 {questions[currentQuestion].questionText} 

وكذلك لقسم الأسئلة:

 {questions[currentQuestion].answerOptions.map((answerOption, index) => ( {answerOption.answerText} ))} 

الآن إذا قمت بتهيئة السؤال الحالي إلى شيء آخر غير 0 ، على سبيل المثال 1 أو 2 ، فسيتم تحديث واجهة المستخدم لعرض السؤال والإجابات لهذا السؤال المحدد. لطيف جدا!

دعنا نضيف بعض التعليمات البرمجية بحيث عندما نضغط على إجابة ، نزيد قيمة CurrentQuestion لنقلنا إلى السؤال التالي.

قم بإنشاء وظيفة جديدة تسمى handleAnswerButtonClick . هذا ما سيتم استدعاؤه عندما ينقر المستخدم على إجابة.

سنزيد قيمة السؤال الحالي بمقدار واحد ، ونحفظه في متغير جديد ، ونضبط هذا المتغير الجديد على الحالة:

const handleAnswerButtonClick = (answerOption) => { const nextQuestion = currentQuestion + 1; setCurrentQuestion(nextQuestion); }; 

بعد ذلك ، أضف حدث onClick إلى زرنا كما يلي:

 handleAnswerButtonClick()}>{answerOption.answerText} 

إذا جربنا هذا ، فسترى أنه يعمل ، حتى نصل إلى النهاية:

بالتالي ماذا حدث؟ حسنًا ، في دالة handleAnswerButtonClick ، نزيد الرقم ونضبطه على الحالة. هذا حسن.

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

دعونا نجري فحصًا للتأكد من أننا لا نتجاوز الحد. في دالة handleAnswerButtonClick ، ​​دعنا نضيف الشرط التالي:

if (nextQuestion < questions.length) { setCurrentQuestion(nextQuestion); } else { alert('you reached the end of the quiz'); } 

يشير هذا بشكل أساسي إلى أنه إذا كان رقم السؤال التالي أقل من إجمالي عدد الأسئلة ، فقم بتحديث الحالة إلى السؤال التالي. وإلا ، فقد وصلنا إلى نهاية الاختبار ، لذا اعرض تنبيهًا في الوقت الحالي.

عرض شاشة النتيجة

بدلاً من إظهار تنبيه ، ما نريد فعله هو إظهار شاشة "النتيجة".

إذا نظرنا إلى JSX ، ستلاحظ أنني وضعت الترميز هنا من أجلك ، نحتاج فقط إلى استبدال كلمة "false" بالمنطق.

فكيف نفعل ذلك؟ حسنًا ، هذا شيء مثالي لوضعه في الحالة!

أضف كائن حالة آخر يخزن سواء كنا نريد إظهار شاشة النتيجة أم لا:

const [showScore, setShowScore] = useState(false); 

واستبدال falseمع showScoreفي منطقتنا JSX:

 {showScore ? // ... score section markup : // ... quiz question/answer markup} 

لن يتغير شيء ، ولكن إذا غيرنا قيمة الحالة إلى "صحيح" ، فستظهر الدرجة div. هذا لأن كل شيء ملفوف في ثلاثية ، وهذا يعني:

"إذا كانت showScore صحيحة ، فقدم ترميز قسم النتيجة ، وإلا ، فقم بعرض ترميز سؤال / إجابات الاختبار"

الآن ، نريد تحديث متغير الحالة هذا عندما يصل المستخدم إلى نهاية الاختبار. لقد كتبنا بالفعل المنطق لهذا في وظيفة handleAnswerButtonClick.

كل ما يتعين علينا فعله هو استبدال منطق التنبيه الذي يقوم بتحديث متغير showScore ليصبح صحيحًا:

if (nextQuestion < questions.length) { setCurrentQuestion(nextQuestion); } else { setShowScore(true); } 

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

حفظ النتيجة

مهمتنا التالية هي الاحتفاظ بنتيجة في مكان ما في تطبيقنا ، وزيادة هذه القيمة إذا اختار المستخدم الخيار الصحيح.

المكان المنطقي للقيام بذلك هو داخل وظيفة “handleAnswerOptonClick”.

تذكر عندما نكرر الأمر على answerOptions ، تعطينا وظيفة الخريطة كائنًا لكل منها يتضمن السؤال ، وقيمة منطقية توضح ما إذا كانت الإجابة صحيحة أم لا. هذه القيمة المنطقية هي ما سنستخدمه لمساعدتنا في زيادة درجاتنا.

في زرنا ، قم بتحديث الوظيفة كما يلي:

onClick={()=> handleAnswerButtonClick(answerOption.isCorrect) 

قم بعد ذلك بتحديث الوظيفة لقبول هذه المعلمة:

const handleAnswerButtonClick = (isCorrect) => { //... other code }; 

يمكننا الآن إضافة بعض المنطق هنا في الدالة. الآن نريد أن نقول "إذا كان isCorrect هو true ، فنحن نريد إظهار تنبيه":

const handleAnswerButtonClick = (isCorrect) => { if (isCorrect) { alert(“the answer is correct!”) } //...other code }; 

هذا هو نفسه if(isCorrect === true)، مجرد نسخة مختصرة. الآن إذا حاولنا ذلك ، فسترى أننا نتلقى تنبيهًا عندما نضغط على الإجابة الصحيحة.

فقط للتلخيص حتى الآن:

  • عندما نكرر فوق الأزرار ، نقوم بتمرير isCorrectالقيمة المنطقية لهذا الزر إلى وظيفة handleAnswerButtonClick
  • في الوظيفة نتحقق مما إذا كانت هذه القيمة صحيحة ونعرض تنبيهًا إذا كانت كذلك.

بعد ذلك ، نريد حفظ النتيجة بالفعل. كيف تعتقد أننا نفعل هذا؟ إذا قلت قيمة الدولة فأنت على صواب!

انطلق وأضف قيمة حالة أخرى تسمى "النتيجة". تذكر أن تسبق الوظيفة لتغيير القيمة بـ "set" حتى يتم تعيينها. قم بالبدء في 0:

const [score, setScore] = useState(0); 

بعد ذلك ، بدلاً من إظهار تنبيه ، نريد تحديث درجاتنا بمقدار 1 إذا حصل المستخدم على الإجابة الصحيحة.

في وظيفة handleAnswerButtonClick ، أزل التنبيه وقم بزيادة درجاتنا بمقدار واحد:

const handleAnswerButtonClick = (isCorrect) => { if (answerOption.isCorrect) { setScore(score + 1); } //...other code }; 

إظهار النتيجة

لإظهار النتيجة ، علينا فقط إجراء تغيير بسيط على كود العرض الخاص بنا. في JSX الخاص بنا ، أزل السلسلة المشفرة في قسم النقاط ، وأضف هذا المتغير الجديد:

 You scored {score} out of {questions.length} 
 You scored {score} out of {questions.length} 

الآن إذا قمنا بتشغيل الإجابات ، فستكون النتيجة ديناميكية وستظهر بشكل صحيح في النهاية!

شيء أخير قبل أن نختتم تطبيق الاختبار الخاص بنا: ستلاحظ أن السؤال الحالي المعروض على واجهة المستخدم دائمًا هو "1" ، نظرًا لأنه مشفر بشكل ثابت. نحن بحاجة إلى تغيير هذا لنكون أكثر ديناميكية.

يستعاض عن "عدد الأسئلة" بما يلي:

 Question {currentQuestionIndex + 1}/{questions.length} 

تذكر أننا بحاجة إلى +1 حيث تبدأ أجهزة الكمبيوتر في العد من 0 وليس 1.

هل تريد المزيد من أفكار المشاريع؟

لماذا لا تحاول بناء بعض مشاريع React لتعزيز تعلمك بشكل أكبر؟ أرسل لك كل أسبوع مشروعًا جديدًا لتجربة مثال عملي وكود بداية ونصائح. اشترك لتحصل على هذا مباشرة في صندوق الوارد الخاص بك!