As I mentioned in some of my prior posts, I am new to testing React Native apps. I am trying to test this function that checks if a person is over 21 years old. I am experiment with the React Native testing to see where I should test components, so currently I put them on two elements arbitrarily. However, when I go to get the element by testID, it says that that the testID cannot be found. Below is where I have them currently/initially -- I moved them around to other locations and was yielding the same response. The test scripts are below:
import '../../../matchMedia.mock';
import React from 'react';
import renderer, { act } from 'react-test-renderer';
import VerificationScreen from '../VerificationScreen';
import { RecoilRoot } from 'recoil';
import { render, fireEvent, screen } from '#testing-library/react-native'
import ReactDOM from 'react-dom';
const mockNavigation = {
navigate: jest.fn(),
addListener: jest.fn()
}
test('renders correctly', () => {
const tree = renderer.create(<RecoilRoot><VerificationScreen navigation= {mockNavigation}/></RecoilRoot>).toJSON();
expect(tree).toMatchSnapshot();
});
test('renders default elements', () => {
const { getAllByText } = render(<RecoilRoot><VerificationScreen navigation= {mockNavigation}/></RecoilRoot>);
expect(getAllByText('Can I see some ID?').length).toBe(1);
expect(getAllByText('You must be of legal drinking age to use this app.').length).toBe(1);
expect(getAllByText('Enter Now').length).toBe(1);
});
test('display error if the user is not 21', () => {
const { getAllByText } = render(<RecoilRoot><VerificationScreen navigation= {mockNavigation}/></RecoilRoot>);
console.log(getAllByText('MMDDYYYY'));
fireEvent.changeText(queryByTestId('Verification.DOB'), '10012021');
fireEvent.press(getByTestId('Verification.Submit'));
})
The component itself is below:
import React from 'react';
import moment from 'moment';
import { View, Text, StyleSheet, TouchableOpacity, TextInput } from 'react-native';
import { COLORS } from '../../styles/COLORS';
import { SHADOWS } from '../../styles/shadows';
import ClickableText from '../widgets/ClickableText';
import Logo from '../widgets/Logo';
import SlideInContainer from '../widgets/SlideInContainer';
import Spacing from '../widgets/Spacing';
import ErrorToast from '../widgets/ErrorToast';
import { handleError } from '../utils/ErrorFunctions';
import useDateOfBirth from './useDateOfBirth';
import setStatusBarColor from '../utils/StatusBarColorFunctions';
const VerificationScreen = ({ navigation }) => {
const [error, setError] = React.useState(null);
const [dateOfBirth, setDateOfBirth] = useDateOfBirth();
const [text, setText] = React.useState(dateOfBirth);
const [inputFocused, setInputFocused] = React.useState(false);
const [setColor] = setStatusBarColor();
const DATE_LENGTH = 8;
const ref = React.useRef(null);
const handleOnPress = () => {
setInputFocused(true);
ref.current.focus();
};
const handleOnBlur = () => {
setInputFocused(false);
};
const onSubmit = () => {
// add validation
if (text.length === DATE_LENGTH) {
const MM = text.substring(0, 2);
const DD = text.substring(2, 4);
const YYYY = text.substring(4);
const years = moment(new Date())
.diff(`${YYYY}-${MM}-${DD}`,
'years', false);
if (years >= 21) {
setDateOfBirth(text);
navigation.navigate('Home');
} else {
handleError('Error: You must be 21 to use this app', setError);
}
} else {
handleError('Error: Please input a valid date', setError);
}
};
React.useEffect(() => {
if (dateOfBirth !== '') {
setText(dateOfBirth);
}
}, [dateOfBirth]);
React.useEffect(() => {
setColor(COLORS.red);
},[])
return (
<View style={styles.container}>
<View style={styles.alignment}>
<TextInput
ref={ref}
value={text}
onChangeText={setText}
onBlur={handleOnBlur}
keyboardType="number-pad"
returnKeyType="done"
textContentType="oneTimeCode"
maxLength={DATE_LENGTH}
style={styles.hidden} />
<SlideInContainer>
<ErrorToast
error={error} />
<Logo />
<Text style={styles.title}>Can I see some ID?</Text>
<Text style={styles.subtitle}>You must be of legal drinking age to use this app.</Text>
<TouchableOpacity
style={styles.dateInputContainer}
onPress={() => handleOnPress()}
activeOpacity={1}>
<Text
style={styles.dateText}
testID='Verification.DOB'>
{'MMDDYYYY'.split('').map((val, i) => {
let ret = '';
if (i < text.length) {
ret = text.charAt(i);
} else {
ret = val;
}
if (i === 1 || i === 3) {
ret += '/';
}
return ret;
})}
</Text>
</TouchableOpacity>
<TouchableOpacity
testID='Verification.Submit'
onPress={() => onSubmit()}
style={styles.buttonContainer}>
<Text style={styles.buttonText}>
Enter Now
</Text>
</TouchableOpacity>
<Spacing vertical={10} />
<Text style={styles.legalText}>By entering this app you are agreeing to our <ClickableText text="Terms of Service" url="https://www.google.com" /> and <ClickableText text="Privacy Policy" url="https://www.google.com" /> </Text>
</SlideInContainer>
</View>
<Text style={styles.disclaimerText}>
You must be at least 21 years of age to drink alcoholic beverages. Do not drink and drive, drink to excess or drink with certain medications or medical conditions. For more information, please visit <ClickableText text="this website" url="http://www.cdc.gov/alcohol/index.htm"/> or contact your health provider.
</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: COLORS.red,
},
noteContainer: {
position: 'absolute',
bottom: 0,
},
alignment: {
flex: 0.65
},
hidden: {
opacity: 0,
},
title: {
fontFamily: 'open-sans-semi',
fontSize: 18,
},
subtitle: {
fontFamily: 'open-sans',
textAlign: 'center',
paddingHorizontal: 8,
fontSize: 15,
paddingTop: 8
},
dateInputContainer: {
padding: 20
},
dateText: {
fontSize: 30,
fontFamily: 'open-sans',
},
buttonContainer: {
backgroundColor: COLORS.green,
paddingVertical: 5,
paddingHorizontal: 35,
borderRadius: 5,
...SHADOWS.button,
},
buttonText: {
color: COLORS.white,
fontSize: 18,
fontFamily: 'open-sans-semi',
},
legalText: {
fontFamily: 'open-sans',
paddingBottom: 20,
paddingHorizontal: 8,
fontSize: 12,
textAlign: 'center'
},
disclaimerText: {
fontFamily: 'open-sans',
fontSize: 12,
position: 'absolute',
bottom: 0,
textAlign: 'center',
justifyContent: 'center'
}
})
export default VerificationScreen;
If additional information is needed, please let me know. Thanks in advance!
You are gettinge rror becaue it cant' find TouchablOpacity. Try to mock it at the top like this-
jest.mock('TouchableOpacity', () => 'TouchableOpacity')
Related
import { Camera, CameraType } from 'expo-camera';
import React, { useRef } from "react";
// import logo from './logo.svg';
import * as tf from "#tensorflow/tfjs";
import * as bodyPix from "#tensorflow-models/body-pix";
import { useState } from 'react';
import { Button, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
//AFTER IMPORT
export default function App() {
const [type, setType] = useState(CameraType.back);
const [permission, requestPermission] = Camera.useCameraPermissions();
const canvasRef = useRef(null);
//next part
const runBodysegment = async () => {
const net = await bodyPix.load();
console.log("BodyPix model loaded.");
// Loop and detect hands
setInterval(() => {
detect(net);
}, 100)
};
//next part
const detect = async (net) => {
const person = await net.segmentPersonParts(video);
console.log(person);
const coloredPartImage = bodyPix.toColoredPartMask(person);
bodyPix.drawMask(
canvasRef.current,
video,
coloredPartImage,
0.7,
0,
false
);
runBodysegment();
if (!permission) {
// Camera permissions are still loading
return <View />;
}
if (!permission.granted) {
// Camera permissions are not granted yet
return (
<View style={styles.container}>
<Text style={{ textAlign: 'center' }}>We need your permission to show the camera</Text>
<Button onPress={requestPermission} title="grant permission" />
</View>
);
}
function toggleCameraType() {
setType(current => (current === CameraType.back ? CameraType.front : CameraType.back));
}
return (
<View style={styles.container}>
<Camera style={styles.camera} type={type}>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.button} onPress={toggleCameraType}>
<Text style={styles.text}>Flip Camera</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
//next part
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
camera: {
flex: 1,
},
buttonContainer: {
flex: 1,
flexDirection: 'row',
backgroundColor: 'transparent',
margin: 64,
},
button: {
flex: 1,
alignSelf: 'flex-end',
alignItems: 'center',
},
text: {
fontSize: 24,
fontWeight: 'bold',
color: 'white',
},
});
};
I want to use body-pix in my react-native app for android .
can any one help me how to do it .
I want my app to open a camera and in my camera there will be a body body-pix working
in my android app
I want my react-native app to work properly with body-pix
I had try it many time time but I can't do it properly
I am facing issues in implementing Webview navigation of website using back button as back button when pressed exits the app.
I implemented a button functionality that uses the browser functionality of going back to the previous page and next page. But, this was not an effective implementation.
Here's my webview code:
import React, { useEffect, useState, useRef } from "react";
import {
View,
Text,
StyleSheet,
SafeAreaView,
StatusBar,
Alert,
BackHandler,
} from "react-native";
import { State, TouchableOpacity } from "react-native-gesture-handler";
import * as firebase from "firebase";
import { loggingOut } from "../API/firebaseMethods";
import { WebView } from "react-native-webview";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import SignIn from "./SignIn";
import SignUp from "./SignUp";
import { useBackHandler } from "#react-native-community/hooks";
import NavigationView from "./NavigationView";
const Tab = createBottomTabNavigator();
const LENNY = "https://www.testbooking.lennyconsulting.com/";
const THEME_COLOR = "#000000";
export default function Dashboard({ navigation }) {
function backActionHandler() {
Alert.alert("", "Are Your Sure To Exit The App?", [
{
text: "No",
onPress: () => null,
style: "cancel",
},
{
text: "Yes",
onPress: () => BackHandler.exitApp(),
},
]);
return true;
}
useBackHandler(backActionHandler);
let currentUserUID = firebase.auth().currentUser.uid;
const [firstName, setFirstName] = useState("");
useEffect(() => {
async function getUserInfo() {
try {
let doc = await firebase
.firestore()
.collection("users")
.doc(currentUserUID)
.get();
if (!doc.exists) {
Alert.alert("No user data found!");
} else {
let dataObj = doc.data();
setFirstName(dataObj.firstName);
}
} catch (err) {
Alert.alert("There is an error.", err.message);
}
}
getUserInfo();
});
const handlePress = () => {
loggingOut();
navigation.replace("Home");
};
const AppStatusBar = ({ backgroundColor, ...props }) => {
return (
<View style={[styles.statusBar, backgroundColor]}>
<StatusBar backgroundColor={backgroundColor} {...props} />
</View>
);
};
const BAR_HEIGHT = StatusBar.currentHeight;
const styles = StyleSheet.create({
statusBar: {
height: BAR_HEIGHT,
},
});
const webViewRef = useRef();
const [canGoBack, setCanGoBack] = useState(false);
const [canGoForward, setCanGoForward] = useState(false);
const handleBackPress = () => {
webViewRef.current.goBack();
};
const handleForwardPress = () => {
webViewRef.current.goForward();
};
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={{ width: "100%", height: "100%" }}>
<WebView
ref={webViewRef}
source={{ uri: LENNY }}
onLoad={console.log("Loaded")}
onNavigationStateChange={(state) => {
const back = state.canGoBack;
const forward = state.canGoForward;
setCanGoBack(back);
setCanGoForward(forward);
}}
/>
<NavigationView
onBackPress={handleBackPress}
onForwardPress={handleForwardPress}
canGoBack={canGoBack}
canGoForward={canGoForward}
/>
<StatusBar style="auto" />
<View>
<Text style={styles.text}>Hi {firstName}</Text>
<TouchableOpacity style={styles.button} onPress={handlePress}>
<Text style={styles.buttonText}>Log Out</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
<SafeAreaView style={styles.topSafeArea} />
<SafeAreaView style={styles.bottomSafeArea}>
<AppStatusBar backgroundColor={THEME_COLOR} barStyle="light-content" />
</SafeAreaView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
topSafeArea: {
flex: 1,
backgroundColor: THEME_COLOR,
},
bottomSafeArea: {
flex: 1,
backgroundColor: THEME_COLOR,
},
button: {
width: 150,
padding: 5,
backgroundColor: "#ff9999",
borderWidth: 2,
borderColor: "white",
borderRadius: 15,
alignSelf: "center",
},
buttonText: {
fontSize: 20,
color: "white",
fontWeight: "bold",
textAlign: "center",
},
container: {
height: "100%",
width: "100%",
backgroundColor: "#3FC5AB",
alignItems: "center",
justifyContent: "center",
},
text: {
textAlign: "center",
fontSize: 20,
fontStyle: "italic",
marginTop: "2%",
marginBottom: "10%",
fontWeight: "bold",
color: "black",
},
titleText: {
textAlign: "center",
fontSize: 30,
fontWeight: "bold",
color: "#2E6194",
},
});
Please someone help me. I am new to React Native.
I'm using React Native Expo. Currently i'm trying to make an application which uses a barcodescanner for scanning QR-code objects. I've implemented a turn camera button for the front or back camera but when i press the button it does nothing only when i switch from one screen to the other. I think there is something wrong with refreshing the screen immediately but i've no clue of how i should solve this problem
Code:
import React, { useEffect, useState, useLayoutEffect } from 'react';
import { StyleSheet, Text, View, Button, Alert, ActivityIndicator, Pressable } from 'react-native';
import { globalStyles } from '../styles/global';
// import { Camera, BarCodeScanningResult } from 'expo-camera';
import { BarCodeScanner } from 'expo-barcode-scanner';
import BarcodeMask from 'react-native-barcode-mask';
import { useIsFocused, useNavigation } from '#react-navigation/native';
import CustomButton from '../components/CustomButton';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
export function ShowLoading(){
return(
<View style={styles.loader}><ActivityIndicator size="large" color='white'/></View>
)
}
export default function Scan(){
const navigation = useNavigation()
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
const [loading, setLoading] = useState(false);
const [type, setType] = useState(BarCodeScanner.Constants.Type.back);
const isFocused = useIsFocused()
useEffect(() => {
(async () => {
const {status} = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
// useEffect(() => {
// if(loading){
// setLoading(true)
// } else {
// setLoading(false)
// }
// },[loading])
const initScanner = async() => {
const {status} = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
}
const handleNavigation = async() => {
setScanned(false)
navigation.navigate('Oefening')
}
const handleNo = () => {
setScanned(false)
}
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true)
setLoading(true)
setTimeout(() => { Alert.alert(
'QR-Code gevonden',
`QR-Code met type ${type} en data ${data} is gescand, wilt u verder gaan?`,
[
{
text: "Nee",
onPress: () => handleNo(),
},
{
text: "Ja",
onPress: () => handleNavigation(),
}
]
), setLoading(false)}, 1000)
}
if (hasPermission === null) {
return <View style={styles.permissionWrapper}>
<Text style={styles.permissionText}>Een moment geduld..</Text>
<ActivityIndicator size='large' color='#1f69b1'></ActivityIndicator>
</View>;
}
if (hasPermission === false) {
return <Text>Geen toegang tot uw camera!</Text>;
}
return (
<View style={{flex: 1, flexDirection: 'column', justifyContent: 'flex-end'}}>
{loading? (<View style={styles.loader}><ActivityIndicator size='large' color='#1f69b1'></ActivityIndicator></View>
) : (
isFocused &&
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
type={type}
>
<View style={styles.topOptions}>
<View style={styles.cameraRotateWrapper}>
<Pressable style={styles.cameraRotate}
onPress={() => {
setType(
type === BarCodeScanner.Constants.Type.back
? BarCodeScanner.Constants.Type.front
: BarCodeScanner.Constants.Type.back
);
}}
>
<Icon name='rotate-3d-variant' size={40} color={'white'}></Icon>
</Pressable>
</View>
</View>
<BarcodeMask edgeColor={'#62B1F6'} showAnimatedLine={true}/>
</BarCodeScanner>)}
{scanned? <View style={styles.searchTextWrapper}><Text style={styles.searchText}>Gevonden!</Text></View> : <View style={styles.searchTextWrapper}><Text style={styles.searchText}>Zoeken naar QR-Code.... </Text></View>}
{/* {scanned? <Button title={'Opnieuw scannen'} onPress={() => setScanned(false)} /> : null} */}
<View style={styles.bottomOptions}>
<CustomButton textValue="Herladen" onPress={initScanner}></CustomButton>
</View>
</View>
)
}
const styles = StyleSheet.create({
loader: {
justifyContent: "center",
alignItems: 'center',
},
permissionWrapper: {
justifyContent: 'center',
alignItems:'center',
margin: 15,
},
permissionText: {
fontSize: 16,
fontWeight: 'bold',
},
topOptions: {
marginTop: 20,
justifyContent: 'space-between',
marginHorizontal: '10%'
},
searchTextWrapper: {
},
searchText: {
color: 'white',
fontSize: 18,
textAlign: 'center',
},
cameraRotateWrapper: {
width: 50,
height: 50,
},
cameraRotate: {
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
borderColor: "white",
backgroundColor: '#1f69b1',
borderRadius: 10,
},
bottomOptions: {
marginHorizontal: '10%',
marginBottom: 10,
},
})
I am working on a (what I thought was) simple agenda app. Using React-Native Calendars to add an Agenda to my page. I wanted to create functionality to add items to the Agenda. I added a placeholder API to fill the Agenda with items so I can add additional styling before I enter in my own logic. I am trying to add a "+" button that will open a prompt to add an item to the Agenda. However, I cannot get the item to stack on top of the Agenda View.
import * as React from 'react';
import {View, StyleSheet, Text, TouchableOpacity, TouchableOpacityComponent, Platform} from 'react-native';
import {Agenda} from 'react-native-calendars';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {useEffect, useState} from "react";
import {addDays, format} from 'date-fns';
import {KeyboardAvoidingView, Touchable} from "react-native-web";
import {ScrollView} from "react-native-gesture-handler";
export default function CalendarView() {
type Item = {
name: string;
}
type Post = {
id: number;
title: string;
body: string;
userId: number;
};
const [items, setItems] = useState();
useEffect(() => {
// run once
const getData = async () => {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts',
);
const data: Post[] = await response.json();
const mappedData = data.map((post, index) => {
const date = addDays(new Date(), index);
return {
...post,
date: format(date, 'yyyy-MM-dd'),
}
})
const reduced = mappedData.reduce(
(acc: { [key: string]: Post[] }, currentItem) => {
const {date, ...coolItem} = currentItem;
acc[date] = [coolItem];
return acc;
},
{},
)
setItems(reduced);
}
getData();
}, []);
const renderItem = (item: Item) => {
return (
<View style={styles.itemContainer}>
<Text>{item.name}</Text>
</View>
);
};
return (
<View style={styles.container}>
<Agenda items={items} renderItem={renderItem}
style={styles.calendarWrapper}
scrollEnabled={true}
theme={{
// calendarBackground: '#000000'
todayTextColor: '#00adf5',
}}>
</Agenda>
<View behavior={Platform.OS === "ios" ? "padding" : "height"}>
<TouchableOpacity onPress={() => console.log("button pressed")}>
<View style={styles.addWrapper}>
<Ionicons name={'add-outline'} size={30} color={'black'}/>
</View>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
calendarWrapper: {},
items: {},
dayPressColor: {
backgroundColor: '#000000'
},
itemContainer: {
backgroundColor: 'white',
margin: 5,
borderRadius: 15,
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
addWrapper: {
width: 100,
height: 100,
backgroundColor: '#55BCF6',
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
borderColor: '#C0C0C0',
borderWidth: 1,
shadowRadius: 5,
shadowOpacity: 100
},
})
Image of the UI so Far
I am extremely new to JS and CSS in general so any help would be appreciated. If I can't get a button to be placed correctly where I want it, then adding the functionality will definitely be a challenge!
I am not able to push the number index in the array of useState.
Where I am going wrong, do I want to push the index of numbers when I click them?
I am extracting the previous state array and then I push new but nothing happens.
How to push a new element inside useState array React hook? My code doesn't work!!
Please someone check.
Game.js
import { StatusBar } from "expo-status-bar";
import React, { useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import RandomNumber from "./RandomNumber";
export default function Game(props) {
const [state, setstate] = useState([]);
let randomNumber = Array.from({ length: props.randomNumberCount }).map(
() => 1 + Math.floor(10 * Math.random())
);
let target = randomNumber
.slice(0, props.randomNumberCount - 2)
.reduce((acc, curr) => acc + curr, 0);
const isNumberSelected = (numberIndex) => {
return state.indexOf(numberIndex) >= 0;
};
const selectNumber = (numberIndex) => {
setstate((arr) => [...arr, numberIndex]);
};
return (
<View style={styles.container}>
<Text style={styles.header}>Target Sum Game</Text>
<Text style={styles.target}>{target}</Text>
<View style={styles.randomContainer}>
{randomNumber.map((randomNumber, index) => (
<RandomNumber
key={index}
id={index}
number={randomNumber}
isSelected={isNumberSelected(index)}
onClick={() => selectNumber}
/>
))}
</View>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#ddd",
paddingTop: 30,
},
target: {
fontSize: 30,
backgroundColor: "#aaa",
margin: 50,
marginHorizontal: 70,
textAlign: "center",
},
header: {
fontSize: 35,
backgroundColor: "dodgerblue",
textAlign: "center",
marginHorizontal: 30,
marginTop: 50,
},
randomContainer: {
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-around",
},
});
RandomNumber.js
import React from "react";
import { StyleSheet, Text, TouchableOpacity } from "react-native";
export default function RandomNumber(props) {
const handlePress = () => {
props.onClick(props.id);
};
return (
<TouchableOpacity onPress={handlePress()}>
<Text style={[styles.random, props.isSelected && styles.selected]}>
{props.number}
</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
random: {
backgroundColor: "#999",
width: 100,
marginHorizontal: 35,
marginVertical: 25,
fontSize: 35,
textAlign: "center",
},
selected: {
opacity: 0.3,
},
});
you are not calling the function
onClick={() => selectNumber(index)}
You need to change the onClick prop and pass the randomNumber (or index depending of what you want to do) to the selectNumber function:
// Not sure if you want to pass randonNumber or index but you get the idea
onClick={() => selectNumber(randomNumber)}
<TouchableOpacity onPress={handlePress()}>
should be
<TouchableOpacity onPress={()=>handlePress()}>
and
() => selectNumber
should be
() => selectNumber()
please try it
Might Be This Helpful:
Home.Js
import React, {useState, useEffect} from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import RandomNumber from './RandomNumber';
const Home = props => {
const [state, setstate] = useState([]);
useEffect(() => {
console.log('state', state);
}, [state]);
let randomNumber = Array.from({length: 10}).map(
() => 1 + Math.floor(10 * Math.random()),
);
let target = randomNumber
.slice(0, props.randomNumberCount - 2)
.reduce((acc, curr) => acc + curr, 0);
const isNumberSelected = numberIndex => {
return state.indexOf(numberIndex) >= 0;
};
const selectNumber = numberIndex => {
console.log('numberIndex', numberIndex);
setstate(arr => [...arr, numberIndex]);
};
return (
<View style={styles.container}>
<Text style={styles.header}>Target Sum Game</Text>
<Text style={styles.target}>{target}</Text>
<View style={styles.randomContainer}>
{randomNumber.map((randomNumber, index) => {
return (
<RandomNumber
key={index}
id={index}
number={randomNumber}
isSelected={isNumberSelected(index)}
onClick={() => selectNumber(randomNumber)}
/>
);
})}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ddd',
paddingTop: 30,
},
target: {
fontSize: 30,
backgroundColor: '#aaa',
margin: 50,
marginHorizontal: 70,
textAlign: 'center',
},
header: {
fontSize: 35,
backgroundColor: 'dodgerblue',
textAlign: 'center',
marginHorizontal: 30,
marginTop: 50,
},
randomContainer: {},
});
export default Home;
RandomNumber.js
import React from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
export default function RandomNumber(props) {
const handlePress = () => {
props.onClick(props.id);
};
return (
<View style={{}}>
<TouchableOpacity onPress={() => handlePress()}>
<Text style={[styles.random, props.isSelected && styles.selected]}>
{props.number}
</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
random: {
backgroundColor: '#999',
width: 100,
height: 100,
marginHorizontal: 35,
marginVertical: 25,
fontSize: 35,
textAlign: 'center',
},
selected: {
opacity: 0.3,
},
});
Output Log: