React Native Speed Math App

سلام به همه، من بعد از 1 سال و 4 ماه برگشتم. این بار با پروژه react native.
بیایید پروژه را شروع کنیم
من این پروژه را با Expo ایجاد کردم و از Expo Router استفاده شده برای مسیریابی استفاده کردم.
یک پوشه جدید ایجاد کنید و ترمینال را باز کنید و این دستور را اجرا کنید
npx create-expo-app@latest
پس از اجرای موفقیت آمیز این دستور، می توانید کد boilerplate را حذف کرده و با یک پروژه جدید شروع به کار کنید. دستور زیر را برای ریست کردن پروژه خود اجرا کنید:
npm run reset-project
قبل از پرش به کد، بیایید عملکرد برنامه خود را درک کنیم.
هنگامی که کاربر در صفحه اصلی است، کاربر باید یک عملیات ریاضی را انتخاب کند که می خواهد تمرین کند.
هنگامی که آنها عملیات را انتخاب کردند، سپس به صفحه آزمون منتقل می شوند و سؤالات در صفحه کاربر ظاهر می شوند. کاربر باید در مدت 10 ثانیه به سوال پاسخ دهد و اگر پاسخ صحیح باشد امتیاز 1 افزایش می یابد و سؤال بعدی ظاهر می شود و اگر کاربر در مدت 10 ثانیه به سؤال پاسخ ندهد سؤال بعدی ارائه می شود.
app
نقطه شروع برنامه ما و داخل است app
، _layout.tsx
چیدمان ریشه ما است و index.tsx
صفحه اصلی ما است
_layout.tsx :-
import { Stack } from "expo-router";
export default function RootLayout() {
return (
);
}
اکنون دو صفحه داریم، یکی صفحه اصلی و دیگری یک صفحه پویا است که سوالات را بر اساس عملیات انتخاب شده توسط کاربر ارائه می دهد.
index.tsx :-
// HomeScreen.js
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import {router} from 'expo-router'
const HomeScreen = () => {
const handleStartQuiz = (operation: string) => {
router.push({pathname:'/quiz/[id]',
params:{id:operation}
}
)
};
return (
<View style={styles.container}>
<Text style={styles.title}>Choose a Operation:</Text>
<Button title="Addition" onPress={() => handleStartQuiz('addition')} />
<Button title="Subtraction" onPress={() => handleStartQuiz('subtraction')} />
<Button title="Multiplication" onPress={() => handleStartQuiz('multiplication')} />
<Button title="Division" onPress={() => handleStartQuiz('division')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
display:'flex',
marginTop:60,
justifyContent: 'center',
// alignItems: 'center',
rowGap:10,
margin:20
},
title: {
fontSize: 20,
marginTop: 20,
},
});
export default HomeScreen;
حالا یک پوشه جدید بسازید app/quiz
و داخل آن مسیری پویا ایجاد می کند [id].tsx
[id]tsx :-
// QuizScreen.js
import { useLocalSearchParams } from 'expo-router';
import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, StyleSheet, SafeAreaView } from 'react-native';
const QuizScreen = () => {
const { id } = useLocalSearchParams<{id:string}>();
const operation = typeof id === 'string' ? id : 'addition'; // Provide a default operation if id is undefined or not a string
const [num1, setNum1] = useState(0);
const [num2, setNum2] = useState(0);
const [userAnswer, setUserAnswer] = useState('');
const [score, setScore] = useState(0);
const [time, setTime] = useState(10);
useEffect(() => {
console.log('Operation from params:', operation);
generateQuestion();
}, [operation]);
const generateQuestion = () => {
switch (operation) {
case 'addition':
setNum1(Math.floor(Math.random() * 100) + 1);
setNum2(Math.floor(Math.random() * 100) + 1);
break;
case 'subtraction':
setNum2(Math.floor(Math.random() * 100) + 1);
setNum1(Math.floor(Math.random() * 100) + 1); // Adjusted to ensure num2 is generated properly
break;
case 'multiplication':
setNum1(Math.floor(Math.random() * 100) + 1);
setNum2(Math.floor(Math.random() * 10) + 1);
break;
case 'division':
const divisor = Math.floor(Math.random() * 9) + 1;
const quotient = Math.floor(Math.random() * 100) + 1;
setNum2(divisor);
setNum1(divisor * quotient);
break;
default:
setNum1(0);
setNum2(0);
}
};
const handleAnswerChange = (text:string) => {
setUserAnswer(text);
const answer = calculateAnswer();
const tolerance = 0.0001; // Adjust tolerance level as needed
if (Math.abs(parseFloat(text) - answer) <= tolerance) {
setScore(score + 1);
handleNextQuestion();
}
};
const calculateAnswer = () => {
switch (operation) {
case 'addition':
return num1 + num2;
case 'subtraction':
return num1 - num2;
case 'multiplication':
return num1 * num2;
case 'division':
return num1 / num2; // Ensure it's a precise division
default:
return num1 + num2; // Default to addition
}
};
const handleNextQuestion = () => {
generateQuestion();
setUserAnswer('');
setTime(10);
};
useEffect(() => {
const timer = setInterval(() => {
setTime((prevTime) => {
if (prevTime > 0) {
return prevTime - 1;
} else {
handleNextQuestion();
return 10; // Reset timer to 10 seconds for the next question
}
});
}, 1000);
return () => clearInterval(timer);
}, []);
return (
<SafeAreaView style={styles.container}>
<Text style={{ fontWeight: 'bold', fontSize: 38 }}>Speed Math</Text>
<View style={styles.topBar}>
<View>
<Text style={styles.timer}><Text>⌛</Text> {time} secText>
</View>
<Text style={styles.score}>Score: {score}</Text>
</View>
<Text style={styles.question}>
{num1} {getOperationSymbol(operation)} {num2} =
</Text>
<TextInput
style={styles.input}
keyboardType="numeric"
value={userAnswer}
onChangeText={handleAnswerChange}
autoFocus={true}
/>
</SafeAreaView>
);
};
const getOperationSymbol = (operation:string) => {
switch (operation) {
case 'addition':
return '+';
case 'subtraction':
return '-';
case 'multiplication':
return '×';
case 'division':
return '÷';
default:
return '+';
}
};
const styles = StyleSheet.create({
container: {
marginTop:50,
flex: 1,
alignItems: 'center',
},
question: {
fontSize: 20,
marginTop: 200,
marginBottom: 10,
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 20,
textAlign: 'center',
width: 100,
},
timer: {
marginTop: 10,
fontSize: 16,
fontWeight: 'bold',
},
score: {
marginTop: 10,
fontSize: 16,
fontWeight: 'bold',
},
topBar: {
flexDirection: 'row',
justifyContent: 'space-between',
gap: 30,
alignItems: 'center',
width: 360,
},
});
export default QuizScreen;
*نکات مهم *
- اینجا،
useLocalSearchParams
از جانبexpo-router
برای استخراج پارامترهای پرس و جو از URL استفاده می شود. -
useLocalSearchParams
را استخراج می کندid
پارامتر از URL، که نوع عملیات حسابی را تعیین می کند. - عملیات نوع عملیات را بر اساس تنظیم می کند
id
یا پیشفرض «افزودن» است. - متغیرهای حالت را مقداردهی اولیه می کنیم:
num1
،num2
،userAnswer
،score
، وtime
.
تابعی برای ایجاد سوالات
const generateQuestion = () => {
switch (operation) {
case 'addition':
setNum1(Math.floor(Math.random() * 100) + 1);
setNum2(Math.floor(Math.random() * 100) + 1);
break;
case 'subtraction':
setNum2(Math.floor(Math.random() * 100) + 1);
setNum1(Math.floor(Math.random() * 100) + 1);
break;
case 'multiplication':
setNum1(Math.floor(Math.random() * 100) + 1);
setNum2(Math.floor(Math.random() * 10) + 1);
break;
case 'division':
const divisor = Math.floor(Math.random() * 9) + 1;
const quotient = Math.floor(Math.random() * 100) + 1;
setNum2(divisor);
setNum1(divisor * quotient);
break;
default:
setNum1(0);
setNum2(0);
}
};
من تازه وارد واکنش نیتیو هستم و شاید در توضیح کد آنقدرها خوب نباشم. با این حال، شما می توانید با من تماس بگیرید
لینکدین
Live Apk
کد