در این آموزش React مبتدی، قصد داریم یک برنامه کویز (آزمون چهار گزینهای) بسازیم. ما با اشیا state پیچیده، نحوه مدیریت hook های مختلف و ارائه موارد بر اساس state کار خواهیم کرد.
آن را بررسی کنید:
خودتان را بسنجید
اگر میخواهید ابتدا خودتان دست به کار شوید، در اینجا سناریوها آورده شده است (همچنین میتوانید کد شروع را در زیر بگیرید):
- وقتی کاربر دکمهای را کلیک میکند، سوال بعدی باید نشان داده شود.
- اگر کاربر سوال را درست پاسخ دهد، باید امتیازش را بگیرد.
- وقتی کاربر به پایان آزمون میرسد، باید نمره کل او نشان داده شود.
کد شروع را از اینجا بگیرید.
بیایید استارت کار را بزنیم
اگر کد شروع کننده را باز کنید و به App.js بروید، خواهید دید که من لیستی از سوالات و پاسخها را که به عنوان آرایهای به نام questions ذخیره شده است، به شما دادهام. این کویز ماست.
هدف اول ما این است که دادههای سوال را از آرایه گرفته و روی صفحه نمایش دهیم.
ما متن کد شده را برداشته و ابتدا دادهها را از سوال اول میگیریم، فقط برای اینکه کارها ادامه پیدا کند. بعدا به تغییر سوالات خواهیم پرداخت.
در JSX، متن سوال رمزگذاری شده را حذف کرده و {[0]questions} را تایپ کنید تا اولین مورد در آرایه سوال ما دریافت شود.
<div className='question-text'>{questions[0]}</div>
رندر کردن (پردازش و ارسال به خروجی) سوالات و پاسخها
اولین سوال یک شی است، بنابراین میتوانیم از "نقطه گذاری" برای دسترسی به خصوصیات استفاده کنیم. اکنون برای دستیابی به متن سوال این شی فقط {question [0].questionText} را انجام خواهیم داد:
<div className='question-text'>{questions[0].questionText}</div>
برنامه را ذخیره و اجرا کنید. به نحوه به روزرسانی متن توجه کنید. به یاد داشته باشید ما در حال گرفتن متن اولین سوال از اولین شی در آرایه سوالات خود هستیم.
در اینجا رویکرد مشابهی در مورد گزینههای پاسخ خواهیم داشت. دکمههای کد شده را بردارید و از تابع map برای جستجوی گزینههای پاسخ برای یک سوال خاص استفاده خواهیم کرد.
حلقههای تابع map را روی آرایه بخاطر بسپارید که آیتم فعلی را که حلقه در حال حاضر روی آن است، به شکل یک متغیر به ما میدهد.
قسمت "بخش پاسخ" را با موارد زیر جایگزین کنید:
<div className='answer-section'>
{questions[0].answerOptions.map((answerOption, index) => (
<button>{answerOption.answerText}</button>
))}
</div>
برنامه را ذخیره و اجرا کنید. توجه کنید که چهار دکمه پاسخ چگونه ظاهر میشود و متن به صورت پویا ارائه میگردد.
بیایید مرور کنیم:
- ما اولین سوال را از آرایه سوالات دریافت میکنیم: questions[0]
- اولین سوال یک شی است که شامل آرایهای از گزینههای پاسخ است. با استفاده از علامت گذاری میتوانیم به این آرایه برسیم: questions[0].answerOptions
- از آنجا که answerOptions یک آرایه است، میتوانیم این را نگاشت کنیم:
questions[0].answerOptions.map - در داخل تابع map، برای هر گزینه یک دکمه میگذاریم و متن را نمایش میدهیم.
تغییر سوالات با استفاده از state
حالا بیایید به JSX خود برگردیم. توجه کنید که اگر questions[0] را به questions[1] یا questions[2] تغییر دهیم، رابط کاربری به روز میشود. به این دلیل است که بسته به ایندکس، دادهها را از سوالات مختلف در آرایه questions میگیرد.
کاری که میخواهیم انجام دهیم این است که برای نگه داشتن سوالی که کاربر در حال حاضر به آن پاسخ میدهد، از یک شی state استفاده کنیم و با کلیک روی دکمه پاسخ، این مورد را به روز کنیم. این کار را میتوانید با اجرای کد در مثال آخر مشاهده کنید.
پیش بروید و یک شی state اضافه کنید که شماره سوال فعلی کاربر را در خود نگه میدارد. این "0" میشود بنابراین کویز اولین سوال را از آرایه میگیرد:
const [currentQuestion, setCurrentQuestion] = useState(0);
اکنون میخواهیم "0" در JSX خود را با این متغیر جایگزین کنیم. ابتدا متن سوال:
<div className='question-text'>{questions[currentQuestion].questionText}</div>
و همچنین برای بخش سوال:
<div className='answer-section'>
{questions[currentQuestion].answerOptions.map((answerOption, index) => (
<button>{answerOption.answerText}</button>
))}
</div>
حال اگر پرسش فعلی را به جای "0"، به عنوان مثال 1 یا 2 قرار دهید، رابط کاربری برای نشان دادن سوال و پاسخهای آن سوال خاص به روز میشود.
بیایید چند قطعه کد اضافه کنیم تا وقتی روی یک جواب کلیک کردیم، مقدار currentQuestion را افزایش دهیم تا ما را به سوال بعدی برساند.
تابع جدیدی به نام handleAnswerButton ایجاد کنید. این همان چیزی است که وقتی کاربر روی پاسخی کلیک میکند فراخوانی میشود.
سپس میخواهیم مقدار سوال فعلی را یک به یک افزایش دهیم، آن را در یک متغیر جدید ذخیره کنیم و این متغیر جدید را به حالت زیر قرار دهیم:
const handleAnswerButtonClick = (answerOption) => {
const nextQuestion = currentQuestion + 1;
setCurrentQuestion(nextQuestion);
};
سپس یک رویداد onClick را به دکمه اضافه کنید مانند این:
<button onClick={() => handleAnswerButtonClick()}>{answerOption.answerText}</button>
اگر این را امتحان کنید، میبینید که تا پایان کار میکند:
چه اتفاقی میافتد؟ در تابع handleAnswerButtonClick ما در حال افزایش تعداد هستیم و آن را روی state تنظیم میکنیم.
اما به یاد داشته باشید که برای دستیابی به گزینههای پرسش و پاسخ، از این شماره برای دسترسی به یک آرایه استفاده میکنیم. وقتی به 5 رسیدیم، چون هیچ عنصر 5 وجود ندارد، میشکند.
بیایید بررسی کنیم تا مطمئن شویم که از حد مجاز عبور نمیکنیم. در تابع handleAnswerButtonClick اجازه دهید شرط زیر را اضافه کنیم:
if (nextQuestion < questions.length) {
setCurrentQuestion(nextQuestion);
} else {
alert('you reached the end of the quiz');
}
این اساسا میگوید اگر شماره سوال بعدی از تعداد کل سوالات کمتر باشد، state را به سوال بعدی به روز کنید. در غیر این صورت، ما به پایان آزمون رسیدهایم، بنابراین اکنون یک هشدار نشان داده میشود.
نمایش صفحه نمرات
کاری که میخواهیم انجام دهیم به جای نشان دادن هشدار، نمایش "نمره" است.
اگر به JSX نگاهی بیندازید، متوجه میشوید که من علامت گذاری را برای شما در اینجا قرار دادهام، فقط باید "false" را با منطق جایگزین کنیم.
خوب چگونه میتوانیم این مسئله را پیش ببریم؟ این یک چیز عالی برای قرار دادن در state است.
شی دیگری را اضافه کنید که هرچه بخواهیم در صفحه نمرات نشان داده شود را ذخیره کنیم:
const [showScore, setShowScore] = useState(false);
و false را در JSX جایگزین showScore کنید:
<div className='app'>{showScore ? <div className='score-section'>// ... score section markup</div> : <>// ... quiz question/answer markup</>}</div>
هیچ چیزی تغییر نخواهد کرد، اما اگر مقدار state را به true تغییر دهیم، div نمرات نشان داده میشود. به این دلیل است که همه چیز در یک ternary آورده شده است، به این معنی:
"اگر showScore مقدار true باشد، بخش نمره را نمایش دهید، در غیر این صورت علامت گذاری سوال / جواب آزمون را ارائه دهید."
اکنون وقتی کاربر به پایان آزمون رسیده است، میخواهیم متغیر state را به روز کنیم. ما قبلا منطق این را در تابع handleAnswerButtonClick خود نوشتهایم.
تمام کاری که ما باید انجام دهیم جایگزینی منطق هشدار است که متغیر showScore را به صورت واقعی به روزرسانی میکند:
if (nextQuestion < questions.length) {
setCurrentQuestion(nextQuestion);
} else {
setShowScore(true);
}
اگر روی پاسخهای آزمون کلیک کنیم، وقتی به پایان میرسیم، قسمت نمره نشان داده میشود. در حال حاضر متن و نمره نشان داده شده یک رشته کد نویسی شده است، بنابراین باید آن را پویا کنیم.
ذخیره نمرات
وظیفه بعدی ما این است که نمرات را در برنامه خود نگه داریم و اگر کاربر گزینه صحیح را انتخاب کرد، این مقدار را افزایش میدهیم.
مکان منطقی برای انجام این کار در تابع "handleAnswerOptonClick" است.
به خاطر بسپارید که هنگام جواب دادن روی repoOption ها، تابع map برای هر کدام یک شی در اختیار ما قرار میدهد که شامل questionText و یک مقدار بولی است که بیان میکند این پاسخ صحیح است یا نه. این boolean همان چیزی است که برای افزایش نمره به ما کمک خواهد کرد.
در دکمه تابع را به صورت زیر به روز کنید:
onClick={()=> handleAnswerButtonClick(answerOption.isCorrect)
تابع بعدی را برای پذیرش این پارامتر به روز کنید:
const handleAnswerButtonClick = (isCorrect) => {
//... other code
};
اکنون میتوانیم در تابع خود منطقی را اضافه کنیم. در حال حاضر میخواهیم بگوییم "اگر isCorrect مقدار true است، میخواهیم یک هشدار را نشان دهیم":
const handleAnswerButtonClick = (isCorrect) => {
if (isCorrect) {
alert(“the answer is correct!”)
}
//...other code
};
این همان نسخهای است که اگر (isCorrect === true)، فقط یک نسخه مختصر است. حالا اگر این را امتحان کنید، خواهید دید که وقتی روی جواب درست کلیک میکنیم، هشدار دریافت میکنیم.
فقط تا اینجا پوشش داده شده:
- وقتی روی دکمه ها تکرار میکنیم، مقدار بولی isCorrect را برای آن دکمه به تابع handleAnswerButtonClick منتقل میکنیم.
- در تابع، بررسی میکنیم که اگر مقدار true است، هشدار نشان داده شود.
بعد میخواهیم در واقع امتیاز را ذخیره کنیم. به نظر شما چگونه این کار را انجام دهیم؟ اگر جوابتان مقدار state است، پس درست حدس زدهاید!
پیش بروید و مقدار state دیگری به نام "score" اضافه کنید. به یاد داشته باشید که پیشوند تابع را با مقدار "set" تغییر دهید تا setScore شود و مقدار اولیه آن را به "0" برسانید:
const [score, setScore] = useState(0);
در مرحله بعدی به جای نشان دادن هشدار، اگر کاربر پاسخ صحیحی دریافت کند، میخواهیم نمره خود را به "1" به روز کنیم.
در تابع handleAnswerButtonClick هشدار را بردارید و نمره را یکی افزایش دهید:
const handleAnswerButtonClick = (isCorrect) => {
if (answerOption.isCorrect) {
setScore(score + 1);
}
//...other code
};
نمایش مقدار نمره
برای نشان دادن نمرات فقط باید یک تغییر کوچک در کد انجام دهیم. در JSX، رشته کد شده را در قسمت نمره حذف کرده و این متغیر جدید را اضافه کنید:
حالا اگر جوابها را اجرا کنیم، نمره به صورت پویاست و در انتها به درستی نمایش داده میشود.
آخرین مورد قبل از اینکه برنامه کویز خود را جمعبندی کنیم، متوجه خواهید شد که سوال فعلی نشان داده شده در رابط کاربری همیشه "1" است، زیرا کد نویسی شده است. برای پویاتر بودن باید این مورد را تغییر دهیم.
<div className='score-section'>
You scored {score} out of {questions.length}
</div>
<div className='score-section'>
You scored {score} out of {questions.length}
</div>
به یاد داشته باشید ما به 1+ احتیاج داریم زیرا کامپیوترها از 0 و نه 1 شروع به شمردن میکنند.
امیدوارم این مقاله برایتان مفید واقع شود و بتوانید این پروژه کوچک را خودتان پیاده سازی کنید. در صورت داشتن هرگونه سوال یا نظری میتوانید آن را در بخش زیر با ما در میان بگذارید.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید