Getting Nan Error in react native timer app - javascript

I have recently started working on react native, and I am currently working on the below code for timer and countdown functionality. Before I am able to put specific time and it is working fine. Also I am able to increment and decrement static values, but on timer getting error.
In the below code while incrementing and decrementing the time, I am getting 'NaN' as output.
//Timing.js
export const Timing = ({ onChangeTime }) => {
return (
<>
<View style={styles.timingButton}>
<RoundedButton size={75} title="+" onPress={() => onChangeTime(onChangeTime + 1)} />
</View>
<View style={styles.timingButton}>
<RoundedButton size={75} title="15" onPress={() => onChangeTime(15)} />
</View>
<View style={styles.timingButton}>
<RoundedButton size={75} title="-" onPress={() => onChangeTime(onChangeTime -1)} />
</View>
</>
);
};
//Timer.js
export const Timer = ({ focusSubject, clearSubject, onTimerEnd }) => {
useKeepAwake();
const [isStarted, setIsStarted] = useState(false);
const [progress, setProgress] = useState(1);
const [minutes, setMinutes] = useState(0.1);
const onEnd = (reset) => {
Vibration.vibrate(PATTERN);
setIsStarted(false);
setProgress(1);
reset();
onTimerEnd(focusSubject);
};
return (
<View style={styles.container}>
<View style={styles.countdown}>
<Countdown
minutes={minutes}
isPaused={!isStarted}
onProgress={setProgress}
onEnd={onEnd}
/>
<View style={{ paddingTop: spacing.xxl }}>
<Text style={styles.title}>Focusing on:</Text>
<Text style={styles.task}>{focusSubject}</Text>
</View>
</View>
<View style={{ paddingTop: spacing.sm }}>
<ProgressBar
progress={progress}
color={colors.progressBar}
style={{ height: spacing.sm }}
/>
</View>
<View style={styles.timingWrapper}>
<Timing onChangeTime = {setMinutes} />
</View>
<View style={styles.buttonWrapper}>
{!isStarted ? (
<RoundedButton title="start" onPress={() => setIsStarted(true)} />
) : (
<RoundedButton title="pause" onPress={() => setIsStarted(false)} />
)}
</View>
<View style={styles.clearSubjectWrapper}>
<RoundedButton size={50} title="-" onPress={clearSubject} />
</View>
</View>
);
};
//Countdown.js
const minutesToMillis = (min) => min * 1000 * 60;
const formatTime = (time) => (time < 10 ? `0${time}` : time);
export const Countdown = ({ minutes = 0.1, isPaused, onProgress, onEnd }) => {
const interval = React.useRef(null);
const [millis, setMillis] = useState(null);
const reset = () => setMillis(minutesToMillis(minutes))
const countDown = () => {
setMillis((time) => {
if (time === 0) {
clearInterval(interval.current);
onEnd(reset);
return time;
}
const timeLeft = time - 1000;
return timeLeft;
});
};
useEffect(() => {
setMillis(minutesToMillis(minutes));
}, [minutes]);
useEffect(() => {
onProgress(millis / minutesToMillis(minutes));
}, [millis]);
// useEffect(() => {
// onIncrement(millis / minutesToMillis(minutes)+1000);
// },[millis]);
useEffect(() => {
if (isPaused) {
if (interval.current) clearInterval(interval.current);
return;
}
interval.current = setInterval(countDown, 1000);
return () => clearInterval(interval.current);
}, [isPaused]);
const minute = Math.floor(millis / 1000 / 60) % (60);
const seconds = Math.floor(millis / 1000) % (60);
return (
<Text style={styles.text}>
{formatTime(minute)}:{formatTime(seconds)}
</Text>
);
};

Change your Timing likewise
export const Timing = ({ onChangeTime }) => {
return (
<>
<View style={styles.timingButton}>
<RoundedButton size={75} title="+" onPress={() => onChangeTime(prev => prev + 1)} />
</View>
<View style={styles.timingButton}>
<RoundedButton size={75} title="15" onPress={() => onChangeTime(15)} />
</View>
<View style={styles.timingButton}>
<RoundedButton size={75} title="-" onPress={() => onChangeTime( prev => prev - 1)} />
</View>
</>
);
};

Related

Can setInterval block user input?

I tried to program a little stopwatch to test something out but after clicking "Start" and its running the "Stop", "Lap" and "Reset" Buttons register the input up to a second or more after I click them. What am I missing here?
My guess is it has something to do with the useEffect hook, but Im not sure since I haven't used React or React Native that extensively.
export default function TabOneScreen({ navigation }: RootTabScreenProps<'TabOne'>) {
const [time, setTime] = useState<number>(0);
const [timerOn, setTimerOn] = useState(false);
const [lapCounter, setLapCounter] = useState<number>(0);
const [laps, setLaps] = useState<{count: number, lapTime: number}[]>([])
useEffect(() => {
var interval: any = null;
if (timerOn) {
interval = setInterval(() => {
setTime((prevTime) => prevTime + 10);
}, 10);
} else if (!timerOn) {
clearInterval(interval);
}
return () => clearInterval(interval);
}, [timerOn]);
return (
<View style={styles.container}>
<Text>time:</Text>
<View style={styles.timer}>
<Text>{("0" + Math.floor(time / 60000) % 60).slice(-2)}:</Text>
<Text>{("0" + Math.floor(time / 1000) % 60).slice(-2)}:</Text>
<Text>{("0" + (time / 10) % 100).slice(-2)}</Text>
</View>
<View style={styles.buttons}>
<Button
title="Start"
onPress={() => setTimerOn(true)}
/>
<Button
title="Stop"
onPress={() => setTimerOn(false)}
/>
<Button
title="Lap"
onPress={() => {
setLapCounter(counter => counter += 1)
setLaps(prevLaps => [
...prevLaps,
{count: lapCounter, lapTime: time}
]
)
}}
/>
<Button
title="Reset"
onPress={() => {
setTimerOn(false)
setTime(0)
setLapCounter(0)
setLaps([])
}
}
/>
</View>
<FlatList
data={laps}
renderItem={({ item }) =>
<View style={styles.lapList}>
<Text style={styles.item}>Lap: {item.count}</Text>
<Text style={styles.item}>{item.lapTime}</Text>
</View>
}
/>
</View>
);
}
On the "else if" you clear an empty interval (because you did not save the previous one anywhere). Create a new hook, such as useTimer.
Or use a premade like: https://www.npmjs.com/package/use-timer

react native: Displays a single table with the data

In my code I expect to get only one table with the data but what happens is that I get a lot of tables with the same data and it is not clear to me why.
Lots of tables are accepted and I should get only one table.
I would be happy to help with this
export const ActionModal = (props: any) => {
const { pointsData } = useGetPoints();
const [tableHead] = useState(['אזור', 'אתר', 'נ`ק איסוף', 'מיקום']);
const [tableData, setTableData] = useState([]);
const arrangeData = () => {
let rows: any[] = [];
pointsData.forEach(e => {
let row = [e.area, e.site, e.gatheringPoint, e.location];
rows.push(row);
});
setTableData(rows);
}
useEffect(() => {
arrangeData();
}, []);
const renderItem = ({ item }: any) => (
<View style={styles.item}>
<View style={styles.tableView}>
<Table borderStyle={{ borderWidth: 2, borderColor: '#c8e1ff' }}>
<Row data={tableHead} style={styles.head} textStyle={styles.text} />
<Rows data={tableData} textStyle={styles.text} />
</Table>
</View>
<Text style={{ fontSize: 18 }}>{item.area}, {item.site}, {item.gatheringPoint}, {item.location}</Text>
</View>
)
return (
<Modal
animationType={'slide'}
transparent={false}
visible={props.actionModalVisible}
onRequestClose={() => {
console.log('Modal has been closed.');
}}>
<View style={styles.modal}>
{pointsData.length ?
<FlatList
data={pointsData}
renderItem={renderItem}
keyExtractor={item => item.gatheringID}
/> :
<ActivityIndicator size="large" />}
</View>
<Button
title="סגור"
onPress={props.onClose}
/>
</Modal>
);
};
Table are rendered inside a item of flatlist
the function renderItem will repeate like a number of row of you array , this why you get lot of table ..
to fix this you need to pull out of flatlist like this to rendering table once time :
export const ActionModal = (props: any) => {
const { pointsData } = useGetPoints();
const [tableHead] = useState(['אזור', 'אתר', 'נ`ק איסוף', 'מיקום']);
const [tableData, setTableData] = useState([]);
const arrangeData = () => {
let rows: any[] = [];
pointsData.forEach(e => {
let row = [e.area, e.site, e.gatheringPoint, e.location];
rows.push(row);
});
setTableData(rows);
}
useEffect(() => {
arrangeData();
}, []);
const renderItem = ({ item }: any) => (
<Text style={{ fontSize: 18 }}>{item.area}, {item.site}, {item.gatheringPoint}, {item.location}</Text>
)
return (
<Modal
animationType={'slide'}
transparent={false}
visible={props.actionModalVisible}
onRequestClose={() => {
console.log('Modal has been closed.');
}}>
<View style={styles.modal}>
{pointsData.length ?
<View style={styles.item}>
<View style={styles.tableView}>
<Table borderStyle={{ borderWidth: 2, borderColor: '#c8e1ff' }}>
<Row data={tableHead} style={styles.head} textStyle={styles.text} />
<Rows data={tableData} textStyle={styles.text} />
</Table>
</View>
<FlatList
data={pointsData}
renderItem={renderItem}
keyExtractor={item => item.gatheringID}
/>
</View>:
<ActivityIndicator size="large" />}
</View>
<Button
title="סגור"
onPress={props.onClose}
/>
</Modal>
);
};

how to handle the toggle states of a common functions in the collapse menu?

I have created a collapse menu and map into the data in render i have also handled the collapse menu which is collapse and expanded as per their specific id. But when i click on the next collapse menu them the previous is close and after click on again the next collpase menu then it will open. I want to write a functionality that when i click on next collapse menu the previous collapse menu is close and next is open at the same time. for example lenskart drawer But i unable to do that
Here's my code:
const SideMenu = (props) => {
const {signOut} = useContext(AuthContext);
const [Routes, setRoutes] = useState([]);
const [expanded, setCollapse] = useState(false);
const [colId, setColID] = useState('');
const [colorId, setColorID] = useState('');
const [reflink, setRefLink] = useState(false);
useEffect(() => {
getData();
}, []);
const getData = () => {
setRoutes(api.getNavigation());
};
const toggleExpand = (id) => {
setColorID(id);
setRefLink(true);
setColID(id);
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setCollapse(!expanded);
};
const changeColor = (id) => {
setColorID(id);
setRefLink(true);
};
console.log('expanded', expanded);
return (
<StrictMode>
<ScrollView contentContainerStyle={styles.scroll}>
<View>
{Routes.map((o, i) =>
o.subarr.length > 0 ? (
<View>
<TouchableOpacity onPress={() => toggleExpand(o.id)}>
<View style={styles.mainContainer}>
<View style={[styles.sidebarDesign]}>
<View style={styles.barIcon}>
<Icon.SimpleLineIcons
name={o.icon}
size={20}
color={
colorId === o.id ? Color.linkColor : Color.gray
}
/>
</View>
<View style={styles.barLabel}>
<Text
style={[
styles.labelStyle,
colorId === o.id
? styles.linkText
: styles.normalText,
]}>
{o.title.toUpperCase()}
</Text>
</View>
<View style={styles.barIcon}>
<Icon.SimpleLineIcons
name={
colId === o.id
? expanded
? 'arrow-up'
: 'arrow-down'
: 'arrow-down'
}
size={20}
color={Color.grayDark}
/>
</View>
</View>
</View>
</TouchableOpacity>
{o.subarr.map((r, j) => (
<View>
{colId === o.id
? expanded && (
<TouchableOpacity
onPress={() => {
props.navigation.navigate(r.label);
changeColor(r.id);
}}>
<View style={[styles.sidebarDesign]}>
<View style={styles.barIcon}>
{/* <Icon.FontAwesome
name={r.icon}
size={20}
color={Color.gray}
/> */}
</View>
<View style={styles.barLabel}>
<Text
style={[
styles.labelStyle,
colorId === r.id
? styles.linkText
: styles.normalText,
]}>
{r.label.toUpperCase()}
</Text>
</View>
<View style={styles.barIcon}>
{/* <Text>icon</Text> */}
</View>
</View>
</TouchableOpacity>
)
: null}
</View>
))}
</View>
) : (
<View>
<TouchableOpacity
onPress={() => {
props.navigation.navigate(o.label);
changeColor(o.id);
}}>
<View style={[styles.sidebarDesign]}>
<View style={styles.barIcon}>
<Icon.SimpleLineIcons
name={o.icon}
size={20}
color={
colorId === o.id ? Color.linkColor : Color.gray
}
/>
</View>
<View style={styles.barLabel}>
<Text
style={[
styles.labelStyle,
colorId === o.id
? styles.linkText
: styles.normalText,
]}>
{o.title.toUpperCase()}
</Text>
</View>
<View style={styles.barIcon}>
{/* <Text>icon</Text> */}
</View>
</View>
</TouchableOpacity>
</View>
),
)}
</View>
</View>
{/* <Divider style={styles.parentHr} /> */}
<View style={styles.containerThree}>
<View style={styles.bottomPart}>
<View>
<TouchableOpacity
onPress={() => {
signOut();
}}>
</StrictMode>
);
};
I am not sure In which form you are getting data but I have created the same scenario in which there are three buttons and onClick of each button the previous message is hidden and next is shown at the same time. I have created the same toggle function as you were asking for go through it once if that's works for you.
export default function Toggle() {
const [toggleOne, settoggleOne] = useState(true);
const [toggleTwo, settoggleTwo] = useState(false);
const [toggleThree, settoggleThree] = useState(false);
const toggleOnefn = () => {
if(toggleOne == true){
settoggleOne(false)
settoggleTwo(true)
}else{
settoggleOne(true)
settoggleTwo(false)
settoggleThree(false)
}
}
const toggleTwofn = () => {
if(toggleTwo == true){
settoggleTwo(false)
settoggleThree(true)
}else{
settoggleTwo(true)
settoggleOne(false)
settoggleThree(false)
}
}
const toggleThreefn = () => {
if(toggleThree == true){
settoggleThree(false)
settoggleOne(true)
}else{
settoggleThree(true)
settoggleTwo(false)
settoggleOne(false)
}
}
return (
<div>
<button onClick={toggleOnefn}>One</button>
{
toggleOne == true ? <p>Data One</p> : ''
}
<br />
<button onClick={toggleTwofn}>One</button>
{
toggleTwo == true ? <p>Data One</p> : ''
}
<br />
<button onClick={toggleThreefn}>One</button>
{
toggleThree == true ? <p>Data One</p> : ''
}
<br />
</div>
);
}

How can i set focus to only one TextInput in list item after TouchableOpacity pressed in this item?

I have a list of many items where each item has TextInput and TouchableOpacity wrapped by View.
I've trying to set focus on TextInput in the list item in which TouchableOpacity has been pressed. It's needed for editing each item's name.
Below is the code of how I tried to do this. The problem of this code is that after pressing on any of the TouchableOpacity the last TextInput will always be focused due to the fact that the last iteration overwrites textInputRef.
Is there a way to make textInputRef contain a reference to the TextInput which TouchableOpacity will press?
const ListComponent = ({list}) => {
const textInputValue = useRef('');
const textInputRef = useRef(null);
changeItemName = (text) => {
textInputValue.current = text;
};
return (
<ScrollView>
{list.length > 0 &&
list.map((item) => (
<View key={item._id}>
<TouchableOpacity>
<View
<Text>{`Item: `}</Text>
<TextInput ref={textInputRef} onChangeText={changeItemName}>
{item.name}
</TextInput>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
textInputValue.current = '';
}}>
<Icon name={'check'} size={25} color="#000" />
</TouchableOpacity>
<View>
<TouchableOpacity
onPress={() => {
textInputValue.current = item.name;
textInputRef.current.focus();
}}>
<Icon name={'edit'} size={25} color="#000" />
</TouchableOpacity>
</View>
</View>
))}
</ScrollView>
);
};
I think creating an array of ref will help you to resolve.
Try this way
const ListComponent = ({list}) => {
const textInputValue = useRef('');
const textInputRef = useRef(null);
changeItemName = (text) => {
textInputValue.current = text;
};
const collectionRef = useRef(list.map(() => createRef()));
return (
<ScrollView>
{list.length > 0 &&
list.map((item, index) => (
<View key={item._id}>
<TouchableOpacity>
<View
<Text>{`Item: `}</Text>
<TextInput ref={collectionRef.current[index]} onChangeText={changeItemName}>
{item.name}
</TextInput>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
textInputValue.current = '';
}}>
<Icon name={'check'} size={25} color="#000" />
</TouchableOpacity>
<View>
<TouchableOpacity
onPress={() => {
textInputValue.current = item.name;
collectionRef[index].current.focus();
}}>
<Icon name={'edit'} size={25} color="#000" />
</TouchableOpacity>
</View>
</View>
))}
</ScrollView>
);
};

undo re-rendering when exiting screen

In my code, I take an email as an input and run a graphql query. Using the graphql query results, I use my showUsersfunction to render some components. When I hit canceland go to the previous screen (toggling), the rendered objects (results of query) should disappear. When I come back to the screen, I am still seeing them. How can I reset them while exiting?
Currently this is what I am doing in my return
{showUsers(userData, Number(numberOfUsers))}
Overview of my code:
export const Page: React.FunctionComponent<PageProps> = ({
toggleShowPage,
showAddFriendEmailPage,
}) => {
const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
const [numberOfUsers, setNumberOfUsers] = useState('');
const validationSchema = emailValidationSchema;
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
for (var i = 0; i < numberOfUsers; i++) {
const userId = data.users.nodes[i].id;
const userName = data.users.nodes[i].firstName
.concat(' ')
.concat(data.users.nodes[i].lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button rounded style={styles.addButton}
//onPress={() => addFriend(Number(data.users.nodes[i].id))}
>
</Button>
</View>
</View>
</View>
);
}
},
[createUserRelationMutation],
);
const addFriend = React.useCallback(
(id: Number) => {
console.log('Whats the Id', id);
createUserRelationMutation({
variables: {
input: { relatedUserId: id, type: RelationType.Friend, userId: 7 },
},
});
},
[createUserRelationMutation],
);
const getFriendId = React.useCallback(
(data: UsersLazyQueryHookResult) => {
if (data) {
if (data.users.nodes.length == 0) {
Alert.alert('User Not Found');
} else {
setUserData(data);
setNumberOfUsers(data.users.nodes.length);
}
}
},
[addFriend],
);
const [loadUsers] = useUsersLazyQuery({
onCompleted: getFriendId,
onError: _onLoadUserError,
});
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
console.log('Submitted');
loadUsers({
variables: {
where: { email: values.email },
},
});
values.email = '';
},
[loadUsers],
);
return (
<Modal
visible={showAddFriendEmailPage}
animationType="slide"
transparent={true}>
<SafeAreaView>
<View style={styles.container}>
<View style={styles.searchTopContainer}>
<View style={styles.searchTopTextContainer}>
<Text
style={styles.searchCancelDoneText}
onPress={toggleShowPage}>
Cancel
</Text>
<Text style={styles.searchTopMiddleText}>
Add Friend by Email
</Text>
<Text style={styles.searchCancelDoneText}>Done</Text>
</View>
<View>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View style={styles.searchFieldContainer}>
<View style={styles.form}>
<FieldInput
handleChange={handleChange}
handleBlur={handleBlur}
value={values.email}
fieldType="email"
/>
<ErrorMessage
name="email"
render={msg => (
<Text style={styles.errorText}>{msg}</Text>
)}
/>
</View>
<View style={styles.buttonContainer}>
<Button
rounded
style={styles.button}
onPress={handleSubmit}>
<Text style={styles.text}>Search </Text>
</Button>
</View>
</View>
)}
</Formik>
</View>
{showUsers(userData, Number(numberOfUsers))}
</View>
</View>
</SafeAreaView>
</Modal>
);
};
This worked for me:
const [isSubmitted, setIsSubmitted] = useState(false);
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
setIsSubmitted(true);
...
},
[loadUsers],
);
{isSubmitted && showUsers(userData, Number(numberOfUsers))}
Upon cancelling, we can setIsSubmitted to false.

Categories

Resources