React native the method onChangeText does not work - reactjs

I am trying to create a function called onHandleWork that takes an input , then I take an input from onChangeText if that input === this.state.count I want that the clock resets however when the clock reach this.state.count nothing happens what are your thoughts?
import React from 'react'
import {Button, StyleSheet,Text,View,TextInput} from 'react-native';
const styles = StyleSheet.create({
appContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
counts: {
fontSize: 48,
}
})
export default class App extends React.Component {
constructor() {
super()
this.state = {
count: 0,
start: true,
}
}
render() {
return(
<View style={styles.appContainer}>
<Text style={styles.counts}>{this.state.count}</Text>
<Button onPress={() => this.onButtonStop()} title="stop"/>
<Button onPress={() => this.onButtonStart()} title="start"/>
<Button onPress={() => this.onClear()}title="clear"/>
<TextInput onChangeText={((value) => this.onHandleWork(value) )} keyboardType="phone-pad" placeholder="time of work"/>
<TextInput placeholder="enter your rest time"/>
</View>
)
}
componentDidMount(){
setInterval(this.inc,1000)
}
onButtonStop(){
clearInterval(this.state.count);
this.setState({start: false})
}
onButtonStart(){
clearInterval(this.state.count);
this.setState({start: true})
}
onClear(){
this.setState({
count:0,
start: false,
})
}
onHandleWork(value) {
if (this.state.count === value) {
clearInterval(this.state.count);
this.setState({
count: 0,
start: false,
})
}
}
inc = () => {
if (this.state.start) {
this.setState(PrevStep => ({
count: PrevStep.count + 1
}))
}
}
}
here is an Image that shows the problem
enter image description here
I want to make it work when the clock is running

Related

set Multiple state Id for custom component in React Native

I have implemented custom inputBox component. So When I am using this component first time then it is working fine and when I am using multiple time in one page then data is prepopulate to next component.
Custom component:
import React, { createRef } from 'react';
import {
View,
TextInput,
Alert,
Text,
StyleSheet
} from "react-native";
class BoxInput extends React.Component {
constructor(props) {
super(props)
this.state = {
digit1: '',
digit2: '',
digit3: '',
...props
}
this.digit1Ref = createRef()
this.digit2Ref = createRef()
this.digit3Ref = createRef()
}
componentDidMount() {
this.digit1Ref.current.focus()
}
componentDidUpdate(prevProps) {
if (this.state.digit1 && this.state.digit2 &&
this.state.digit3
}
saveText(text, key) {
this.setState({ ...this.state, [key]: text }, () => {
if (text) {
key == 'digit1' ? this.digit2Ref.current.focus() : null
key == 'digit2' ? this.digit3Ref.current.focus() : null
key == 'digit3'
}
const boxInputValue = this.state.digit1 + this.state.digit2 + this.state.digit3
this.props.onBoxInput(boxInputValue)
});
}
render() {
return (
<>
<TextInput maxLength={1} keyboardType={'numeric'} ref={this.digit1Ref} style={styles.boxStyle} value={this.state.digit1} onChangeText={(text) => this.saveText(text, 'digit1')} />
<TextInput maxLength={1} keyboardType={'numeric'} ref={this.digit2Ref} style={styles.boxStyle} value={this.state.digit2} onChangeText={(text) => this.saveText(text, 'digit2')} />
<TextInput maxLength={1} keyboardType={'numeric'} ref={this.digit3Ref} style={styles.boxStyle} value={this.state.digit3} onChangeText={(text) => this.saveText(text, 'digit3')} />
</>
)
}
}
const styles = StyleSheet.create({
boxStyle: {
marginTop: 20,
height: 57,
width: 50,
borderRadius: 10,
borderWidth: 1,
borderColor: '#F1F5F9',
backgroundColor: '#F1F5F9',
fontSize: 20,
lineHeight: 40,
paddingHorizontal: 15,
textAlign: 'center'
}
})
export default BoxInput;
import React, { createRef } from 'react';
import styles from './style';
import {
View,
TextInput,
Alert
} from "react-native";
import { connect } from "react-redux";
import * as Animatable from 'react-native-animatable';
import BoxInput from "../../../../md-components/atoms/boxinput"
class MPINScreen extends React.Component {
constructor(props) {
super(props)
this.state = {
confirmMpinEnable: true,
...props
}
this.codes = [{
value: '+91',
}]
}
componentDidUpdate(prevProps) {
if (this.state.mpinValue.split("").length == 3 &&
prevProps.success_msg != this.props.success_msg && this.props.success_msg == 'verified') {
NavigationService.navigate(this.props.navigation, 'MPINVerifyOnboarding')
}
}
handleSubmit = () => {
if (this.state.mpinValue != this.state.confirmMpinValue) {
Alert.alert(
"Error",
"MPIN is not machted",
[
{ text: "OK" }
],
{ cancelable: false }
);
} else {
this.props.verifyMpin({
"mpin": this.state.mpinValue,
phoneNumber: this.props.mobileNumber
})
}
}
mpinConfirmation = () => {
if (this.state.mpinValue.split("").length != 6) {
Alert.alert(
"Error",
"Please insert 6 digit mpin",
[
{ text: "OK" }
],
{ cancelable: false }
);
}else{
this.setState({
confirmMpinEnable: false,
});
}
}
mpinText = (args) => {
this.setState({
mpinValue: args,
});
}
confirmMpinText = (args) => {
this.setState({
confirmMpinValue: args,
});
}
render() {
return (
<>
<HeaderComponent backgroundColor="#E5E5E5" showLeftIcon={true} showRightIcon={false} />
<View style={styles.container}>
<Text style={[styles.textInfo, styles.textTitle]}>We are almost there!</Text>
<View style={styles.imageWrapper}>
<Animatable.View animation="slideInDown" iterationCount={1} style={styles.centerIconWrap}>
<Image style={styles.centerIcon} source={mpin_card} />
</Animatable.View>
</View>
{this.state.confirmMpinEnable ?
<Text style={[styles.textInfo]}>Setup your MPIN</Text> : <Text style={[styles.textInfo]}>Confirm your MPIN</Text>
}
{this.state.confirmMpinEnable ?
<View style={styles.rowWrap}>
<BoxInput id="catFood1" onBoxInput={this.mpinText} />
</View>:
<View style={styles.rowWrap}>
<BoxInput id="catFood2" onBoxInput={this.confirmMpinText} />
</View>
}
<View style={styles.marginBottom}>
<Text style={[styles.mpinNote]}>M-PIN is a short 6-digit PIN that you have to set for</Text>
<Text style={[styles.mpinNote]}>our mandatory Two-Factor Authentication</Text>
</View>
<View style={styles.bottomBtnSyle}>
<View style={styles.multipleBtnStyle}>
<Button onPress={this.handleBack}>{"Back"}</Button>
</View>
{this.state.confirmMpinEnable ?
<View style={styles.multipleBtnStyle}>
<Button onPress={this.mpinConfirmation} >{"Confirm"}</Button>
</View> :
<View style={styles.multipleBtnStyle}>
<Button onPress={this.handleSubmit} >{"Save & Continue"}</Button>
</View>
}
</View>
</View>
</>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MPINScreen);
when I am click on confirm button then hide and display . But in second component data is prepopulating which i was inserted.
in this screen shot data is prepopulate but i want this empty, Because user has to insert again. but it is taking same value from previous state. how we can use multiple time same component in one page.
General idea:
Create a property in MPINScreen state that is changing (incrementing) every attempt (you can call it attempt) and pass it as prop to BoxInput.
In BoxInput create a reset function (that will clean the values of the text inputs and focus the first input). On componentDidUpdate check if attempt prop changed. If true - save the new value in BoxInput state and call "reset".

React Native Expo AV - Implementing SeekBar

I am attempting to use react-native-slider with Expo AV to create a seekbar, but am having trouble updating the 'value' state of slider. When I try to set it to currentPosition/durationPosition, it errors out, likely because initially these values are NaN. I CAN display current/duration however.
My best guess is that I need a way to wait until my mp3 is loaded before rendering the SeekBar. I probably also need to do a better job of separating components and keep PlayerScreen very minimal. I've messed around with this code so much I can barely remember what I've tried... Getting close to ditching Expo because react-native-track-player looks easier to work with and I've heard some bad things about Expo. Anyways, here's where I'm at now
export default class PlayerScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
isPlaying: false,
playbackObject: null,
volume: 1.0,
isBuffering: false,
paused: true,
currentIndex: 0,
durationMillis: 1,
positionMillis:0,
sliderValue:0,
isSeeking:false,
}
}
async componentDidMount() {
try {
await Audio.setAudioModeAsync({
allowsRecordingIOS: false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,
shouldDuckAndroid: true,
staysActiveInBackground: true,
playThroughEarpieceAndroid: true
})
this.loadAudio()
} catch (e) {
console.log(e)
}
}
async loadAudio() {
const { currentIndex, isPlaying, volume} = this.state
try {
const playbackObject = new Audio.Sound()
const source = {
uri: this.props.route.params.item.uri
}
const status = {
shouldPlay: isPlaying,
volume,
}
playbackObject.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate)
await playbackObject.loadAsync(source, status, true)
this.setState({playbackObject})
var sliderValue = this.state.positionMillis/this.state.durationMillis
} catch (e) {
console.log(e)
}
}
handlePlayPause = async () => {
const { isPlaying, playbackObject } = this.state
isPlaying ? await playbackObject.pauseAsync() : await playbackObject.playAsync()
this.setState({
isPlaying: !isPlaying
})
}
onPlaybackStatusUpdate = status => {
this.setState({
isBuffering: status.isBuffering,
durationMillis: status.durationMillis,
positionMillis: status.positionMillis,
})
}
render() {
const { item } = this.props.route.params;
return (
<View style={globalStyles.container}>
<Header />
<View style={globalStyles.subHeader}>
<Text style={globalStyles.title}>{ item.title }</Text>
</View>
<View style={styles.text}>
<Text>{ item.text }</Text>
</View>
<SeekBar
durationMillis={this.state.durationMillis}
positionMillis={this.state.positionMillis}
sliderValue={this.state.sliderValue}
/>
And here's the SeekBar component:
const SeekBar = ({
positionMillis,
durationMillis,
sliderValue
}) => {
return (
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1 }} />
<Text style={[styles.text, { width: 40 }]}>
{positionMillis + ' / ' + durationMillis}
</Text>
</View>
<Slider
minimumValue={0}
maximumValue={1}
value={sliderValue}
style={styles.slider}
minimumTrackTintColor='#fff'
maximumTrackTintColor='rgba(255, 255, 255, 0.14)'
/>
</View>
);
};
export default SeekBar;
put
<SeekBar
durationMillis={this.state.durationMillis}
positionMillis={this.state.positionMillis}
sliderValue={this.state.sliderValue}
/>
in the screen component and
const SeekBar = ({
positionMillis,
durationMillis,
sliderValue
}) => {
sliderValue = positionMillis/durationMillis
return (
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1 }} />
in the SeekBar component

How to sync & increment a value within a Text Input when a numeric value is entered in React Native

I have a counter button that decreases/increases the number in my text input by one. My counter is set initially to 0 and if i press the increase button it increases by 1. However if I delete the initial 0 and manually type in a number, the counter button will increment it to the value 1.
How do I fix this?
Also how do I prevent the number from going higher than 99 and less than 1 because the maxValue and minValue don't seem to be working.
ShopAttack.js
import React from 'react';
import { Badge } from 'native-base';
import {MaterialIcons as Icon} from '#expo/vector-icons';
import {
View,
Text,
TextInput,
Dimensions,
TouchableOpacity,
StyleSheet,
Image,
TouchableWithoutFeedback,
FlatList
} from 'react-native';
import image from '../assets/Images/ShoeJackCityLogo.png';
import { ifIphoneX } from 'react-native-iphone-x-helper';
import Modal from 'react-native-modal';
import { commonStyles } from './styles/styles';
class ShopAttack extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
isModalVisible: false,
show: true,
}
[![}][1]][1]
IncrementItem = () => {
if(this.state.tempNum){
this.setState({ counter: this.state.counter + this.state.tempNum, tempNum: null });
}
else{
this.setState({ counter: this.state.counter + 1 });
}
}
DecrementItem = () => {
this.setState({ counter: this.state.counter - 1 });
}
ToggleClick = () => {
this.setState({ show: !this.state.show });
}
handleOnTextChange = (text) => {
const number = parseInt(text)
if(number){
this.setState({tempNumber: number})
}
}
_toggleModal = () =>
this.setState({ isModalVisible: !this.state.isModalVisible });
<View style={[commonStyles.row, commonStyles.alignSelfcenter]}>
<TouchableOpacity onPress={() => this.IncrementItem()}>
<View
style={[styles.counterButton]}
>
<Icon
type="MaterialIcons"
name="add"
size={40}
style={[
commonStyles.alignSelfcenter,
commonStyles.justifyCenter
]}
/>
<Text
style={[
commonStyles.inventrytextbutton,
commonStyles.white,
{}
]}
>
</Text>
</View>
</TouchableOpacity>
<View
style={[
styles.inventrybar,
styles.alignSelfcenter,
styles.row,
]}
>
<Icon
type="MaterialIcons"
name="monetization-on"
style={[
commonStyles.font16,
commonStyles.alignSelfcenter,
commonStyles.ml15,
{
color: '#C8A74D'
}
]}
/>
<TextInput
keyboardType = 'numeric'
onChange = {this.handleOnTextChange}
maxValue={99}
minValue={0}
style={[
commonStyles.inventrybartextbutton,
commonStyles.redText,
commonStyles.ml5
]}
>
{this.state.counter}
</TextInput>
</View>
<TouchableOpacity onPress={() => this.DecrementItem()}>
<View
style={[styles.counterButton]}
>
<Icon
type="MaterialIcons"
name="remove"
size={40}
style={[
commonStyles.alignItems,
commonStyles.justifyCenter
]}
/>
<Text
style={[
commonStyles.inventrytextbutton,
commonStyles.white,
{}
]}
>
</Text>
</View>
</TouchableOpacity>
</View>
Main Focus Point
//When I enter a value inside the textbox(TextInput because this is react //native) the increment button does not increment the value I entered. I //could send you a screen recording/screenshot via email or something.
import React, { Component } from 'react';
import {
View,
TextInput,
TouchableOpacity,
} from 'react-native';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
class App extends Component {
constructor() {
super();
this.state = {
name: 'React',
counter: 0,
error:''
};
}
//my code
IncrementItem = () => {
if(this.state.tempNum){
let sum = parseInt(this.state.counter) + parseInt(this.state.tempNum);
if(sum >=1 && sum <=99){
this.setState({ counter: sum, tempNum: null });
}else{
console.log("Number should be between 1 and 99");
this.setState({error:"Number should be between 1 and 99"})
}
}
else{
this.setState({ counter: this.state.counter + 1 });
}
}
DecrementItem = () => {
this.setState({ counter: this.state.counter - 1 });
}
handleOnTextChange = (e) => {
const number = e.target.value;
console.log(number)
if(number){
this.setState({[e.target.name]: number})
}
}
render() {
return (
<View>
<TouchableOpacity onPress={() => this.IncrementItem()}/>
<TextInput
keyboardType = 'numeric'
returnKeyType="done"
type="text"
name="tempNum"
value={this.state.tempNum}
onChange = {this.handleOnTextChange}
maxValue={99}
minValue={0}
>
{this.state.counter}
</TextInput>
<TouchableOpacity onPress={this.DecrementItem}>
style={[styles.counterButton]}
>
</TouchableOpacity>
</View>
);
}
}
render(<App />, document.getElementById('root'));
Some issue's are,
You are setting tempNumber state variable
this.setState({tempNumber: number})
but accessing tempNum which is a typo here,
if(this.state.tempNum){
this.setState({ counter: this.state.counter + this.state.tempNum, tempNum: null });
}
Just change tempNumber to tempNum or vice-versa.
When you don't want to pass any value to function, don't do this,
<TouchableOpacity onPress={() => this.IncrementItem()}>
you just need this,
<TouchableOpacity onPress={this.IncrementItem}> // same for DecrementItem
Another issue is,
this.setState({ counter: this.state.counter + this.state.tempNum, tempNum: null })
When you set a state, it is possible that state value is stored as string, so doing this.state.counter + this.state.tempNum might result in string concatination, you can do this,
this.setState({ counter: parseInt(this.state.counter) + parseInt(this.state.tempNum), tempNum: null })
Simplified Demo.
For preventing the number from going higher than 99 and less than 1,
IncrementItem = () => {
if(this.state.tempNum){
let sum = parseInt(this.state.counter) + parseInt(this.state.tempNum);
if(sum >=1 && sum <=99){
this.setState({ counter: sum, tempNum: null });
}else{
console.log("Number should be between 1 and 99");
this.setState({error:"Number should be between 1 and 99"})
}
}else{
this.setState({ counter: this.state.counter + 1 });
}
}
You can check same for DecrementItem.
There is a typo error in your code.
this.setState({tempNumber: number}) should be this.setState({tempNum: number})
And you should define tempNum state in the constructor like
this.state = {
tempNum: null
}
There is a react-native-numeric-input library that supports numeric input.
https://www.npmjs.com/package/react-native-numeric-input

Understanding React Natives setState and componentWillMount from FlatList

So I'm trying to make a simple application with expo and expo audio that will generate a list of audio buttons and text. But I cannot figure out how react works regarding redrawing the setState OUTSIDE componentWillMount and how to remake a soundobject with a new URI
So right now it will work but only playing the FIRST uri, I assume this is because the object still exists.
And it will not change the state of the button, I know this is because react cant see its changing for some reason from FlatList
It works outside of it, if I only make one button in renders view.
FlatList will render the setStates if I use LegacyImplementation=true .. But Im warned this is deprecated. And it renders it for all buttons at the same time
This is my handlerClass:
export class TSSGetter extends React.Component {
constructor(props){
super(props);
this.state ={
isLoading: true,
playingStatus: "Play"
}
}
retrieveData() {
const endpoint = 'http://127.0.0.1:3333/get'
const data = {
"userId": "123412341234",
"hmac": "detteerikkeenrigtighmac"
}
return new Promise((resolve, reject) => {
fetch(endpoint, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'application/json'
},
body: JSON.stringify(data)
})
.then((resp) => {
console.log('hej return')
return resp.json();
})
.then((resp) => {
resolve(resp);
console.log('resp')
}).catch(function(error) {
console.log(error,'naeh')
});
});
}
componentDidMount(){
this.retrieveData()
.then((resp) => {
var pages = resp.books.contentObjects
pages.map((userData) => {
console.log('superduper pages', userData.contentObjectId)
})
this.setState({
isLoading: false,
dataSource: resp.books.contentObjects,
dataroot: resp.books
});
}).catch((err) => {
//handle error
console.log("Api call error2");
alert(err);
})
}
async _playRecording(AudioURL) {
console.log(AudioURL)
const { sound } = await Audio.Sound.createAsync(
{uri: AudioURL},
{
shouldPlay: true,
isLooping: true,
},
this._updateScreenForSoundStatus,
);
this.sound = sound;
this.setState({
playingStatus: 'playing'
});
}
_updateScreenForSoundStatus = (status) => {
if (status.isPlaying && this.state.playingStatus !== "playing") {
this.setState({ playingStatus: "playing" });
} else if (!status.isPlaying && this.state.playingStatus === "playing") {
this.setState({ playingStatus: "donepause" });
}
};
async _pauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
console.log('pausing...');
await this.sound.pauseAsync();
console.log('paused!');
this.setState({
playingStatus: 'donepause',
});
} else {
console.log('playing...');
await this.sound.playAsync();
console.log('playing!');
this.setState({
playingStatus: 'playing',
});
}
}
}
_syncPauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
this.sound.pauseAsync();
} else {
this.sound.playAsync();
}
}
}
_playAndPause = (AudioURL) => {
console.log(AudioURL)
switch (this.state.playingStatus) {
case 'Play':
this._playRecording(AudioURL);
break;
case 'donepause':
case 'playing':
this._pauseAndPlayRecording();
break;
}
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
const styling = {
flex: 1,
paddingTop:10
// flexDirection: 'row'
}
const data = this.state.dataroot;
return(
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) =>
<View>
<TouchableOpacity style={styles.button} onPress={() => this._playAndPause(item.AudioURL)}>
<Text style={styles.buttonText}>
{this.state.playingStatus}+ {item.contentObjectId}
</Text>
</TouchableOpacity>
<Text style={styles.description}>
{item.text},
</Text>
</View>
}
keyExtractor={(item, index) => item.contentObjectId}
/>
</View>
);
}
}
UPDATE: setting extraData={this.state} in flatlist updates the button.. But all the buttons. How do I change the scope of the button?
You could create a specific component for the items in the FlatList. Each of the items will then have their own state.
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { FlatList } from "react-native-gesture-handler";
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => index.toString()}
data={[1, 2, 3, 4, 5]}
renderItem={({ item }) => <Sound />}
/>
</View>
);
}
}
class Sound extends Component {
constructor() {
super();
this.state = {
status: "IDLE"
};
}
onChangeState = value => {
this.setState({
status: value
});
};
render() {
const { status } = this.state;
return (
<View style={{width: 200,paddingVertical: 10}}>
<Text>Status: {status}</Text>
<View style={{ flex: 1,flexDirection: "row", justifyContent: "space-between" }}>
<Text onPress={() => this.onChangeState("PLAYING")}>PLAY</Text>
<Text onPress={() => this.onChangeState("STOPPED")}>STOP</Text>
<Text onPress={() => this.onChangeState("PAUSED")}>PAUSE</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 100,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
I checked out in the docs, here, and I saw that it will re-render just if you pass the state prop, see this explanations:
By passing extraData={this.state} to FlatList we make sure FlatList itself will re-render when the state.selected changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.

Calling Method in React Native using Refs Does Nothing

I'm making a simple pomodoro app in React Native, and I came across a problem with calling a method from a child component. In the code below, the method I am trying to call is reset, which I call from resetTimer in the parent. This does not work, though no errors are produced; console.logging within the method also produces nothing. I followed the model outlined here in the docs. Any help resolving this issue would be appreciated!
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
class Timer extends React.Component {
constructor(props) {
super(props)
this.state = {
minutes: 25,
seconds: 0,
pomodoro: props.pomodoro,
}
}
componentDidMount() {
this.interval = setInterval(this.decrement, 1000)
}
reset = () => {
this.setState(prevState => ({
minutes: (prevState.pomodoro ? 5 : 25),
seconds: 0,
}))
}
decrement = () => {
if ((this.state.minutes+this.state.seconds)===0){
this.setState(prevState => ({
pomodoro: !prevState.pomodoro,
minutes: (prevState.pomodoro ? 25 : 5),
}))
} else{
if (this.props.start){
if (this.state.seconds===0){
this.setState(prevState => ({
minutes: prevState.minutes - 1,
seconds: 59,
}))
} else{
this.setState(prevState => ({
seconds: prevState.seconds - 1
}))
}
}
}
}
render() {
return (
<Text style={styles.time}>
{("0"+this.state.minutes).slice(-2)}:
{("0"+this.state.seconds).slice(-2)}
{this.props.start}
</Text>
);
}
}
export default class App extends React.Component {
constructor (props) {
super(props)
this.state = {
start: false,
pomodoro: false,
buttonText: "Start"
}
}
toggleStart = () => this.setState(prevState => ({
start: !prevState.start,
buttonText: (prevState.start ? "Start" : "Stop")
}))
resetTimer = () => {
this.toggleStart()
this._timer.reset()
}
render() {
return (
<View style={styles.container}>
<Timer
start={this.state.start}
pomodoro={this.state.pomodoro}
reset={this.state.reset}
toggleStart={() => this.toggleStart}
ref={component => { this._timer = component; }}
/>
<View style={styles.buttonRow}>
<Button
title={this.state.buttonText}
onPress={this.toggleStart}>
</Button>
<Button
title="Reset"
onPress={this.resetTimer}>
Timer.resetTime
</Button>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
time: {
fontSize: 70,
color: 'tomato',
alignItems: 'center',
justifyContent: 'center',
},
buttonRow: {
flexDirection: 'row'
},
});
Usually, you shouldn't have to call a childs function in the parent. When you find yourself in this situation, you might be overcomplicating your component structure. Why not move the reset button into the Timer component?
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
class Timer extends React.Component {
constructor(props) {
super(props)
this.state = {
minutes: 25,
seconds: 0,
pomodoro: props.pomodoro,
}
}
componentDidMount() {
this.interval = setInterval(this.decrement, 1000)
}
reset = () => this.setState(prevState({
minutes: (prevState.pomodoro ? 5 : 25),
seconds: 0,
}))
decrement = () => {
if ((this.state.minutes+this.state.seconds)===0){
this.setState(prevState => ({
pomodoro: !prevState.pomodoro,
minutes: (prevState.pomodoro ? 25 : 5),
}))
} else{
if (this.props.start){
if (this.state.seconds===0){
this.setState(prevState => ({
minutes: prevState.minutes - 1,
seconds: 59,
}))
} else{
this.setState(prevState => ({
seconds: prevState.seconds - 1
}))
}
}
}
}
render() {
return (
<View>
<Text style={styles.time}>
{("0"+this.state.minutes).slice(-2)}:
{("0"+this.state.seconds).slice(-2)}
{this.props.start}
</Text>
<View style={styles.buttonRow}>
<Button
title={this.props.buttonText}
onPress={this.props.toggleStart}>
</Button>
<Button
title="Reset"
onPress={this.reset}>
Timer.resetTime
</Button>
</View>
</View>
);
}
}
export default class App extends React.Component {
constructor (props) {
super(props)
this.state = {
start: false,
pomodoro: false,
buttonText: "Start"
}
}
toggleStart = () => this.setState(prevState => ({
start: !prevState.start,
buttonText: (prevState.start ? "Start" : "Stop")
}))
render() {
return (
<View style={styles.container}>
<Timer
start={this.state.start}
pomodoro={this.state.pomodoro}
toggleStart={this.toggleStart}
buttonText={this.state.buttonText}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
time: {
fontSize: 70,
color: 'tomato',
alignItems: 'center',
justifyContent: 'center',
},
buttonRow: {
flexDirection: 'row'
},
});

Resources