React-native: Pass event to other object - javascript

This is my first experience with JS/React/React Native. I don't yet fully grasp mechanics of this framework, so be kind to me.
What I have :
<View style={styles.container}>
<View style={styles.timerContainer}>
<View style={styles.timerBar}>
<Image style={styles.icon} source={require('../../img/time50.png')}/>
{Timer} //First
</View>
<View style={styles.timerBar}>
<Image style={styles.icon} source={require('../../img/break50.png')}/>
{Timer} //Second
</View>
</View>
<View style={styles.buttonContainer}>
<TouchableHighlight onPress={this.startWork}>
<Image style={styles.imageButton} source={require('../../img/start.png')}/>
</TouchableHighlight>
<TouchableHighlight onPress={this.startBreak}>
<Image style={styles.imageButton} source={require('../../img/break.png')}/>
</TouchableHighlight>
<TouchableHighlight onPress={this.stopWork}>
<Image style={styles.imageButton} source={require('../../img/end.png')}/>
</TouchableHighlight>
</View>
</View>
Timer is a custom class, which will have 'start', 'pause' and 'end' methods. I want to call methods of both Timers when TouchableHighlight is pressed.
Overall it would look like this :
when first TouchableHighlight is pressed (startWork), Timer2.end and Timer1.start should be called, when second is pressed (startBreak), Timer1.pause, Timer2.start should be called, for third (stopWork) it would be Timer1.end, Timer2.end.
But how am I supposed to refer to these timers from onPress methods? Should I keep both Timers in some vars of parent class? I am totally stuck and have no idea where to start (and what's acceptable). Such problem is not easily googlable (or I don't know where to look). I would appreciate any help (solution, pointing to tutorial...).

When you render the timer components in this component you should assign a ref to each one of them, like
<Timer ref={r => this.timer1 = r}/>
Then in the Touchable callback functions you can call this.timer1.start()
Note: Cleaner ref setting would be to actually have another function, so you aren't constantly binding in the render function:
setTimerOne = (r) => {
this.timer1 = r;
}
render() {
<Timer ref={this.setTimerOne}/>
}

Related

Warning: Cannot update a component from inside the function body of a different component. in TouchableOpacity

I got this error
Warning: Cannot update a component from inside the function body of a different component.
How to fix this ?
When I remove touchable opacity, it's not showing anymore
<View style={styles.SaD}>
<TouchableOpacity onPress={(e) = props.locationSetState(1)}> // here
<Text style={styles.text1}>Choose your starting point</Text>
</TouchableOpacity>
<TouchableOpacity onPress={(e) = props.locationSetState(2)}>
<Text style={styles.text1}>Choose destination</Text>
</TouchableOpacity>
</View>
details are not sufficient to understand your problem but according to what I understand from your code try using react hooks and try this
function App() {
const [state,setState]=React.useState(null);
console.log(state);
return (
<View style={styles.SaD}>
<TouchableOpacity onPress={(e) => setState(1)}>
<Text style={styles.text1}>Choose destination</Text>
</TouchableOpacity>
<TouchableOpacity onPress={(e) => setState(2)}>
<Text style={styles.text1}>Choose destination</Text>
</TouchableOpacity>
</View>
);
}

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'search'

The search is perfect and it's all looks fine, but gets this warning.
I get this warning when I press any key to start the search method.
"Song_ID", "Song_Name" and "Image" are of the variable names from the SQL Database.
- I looked on other question as this, but it didn't help me at all.
This is the code where the error is :
return (
<View>
<ScrollView>
{musicList.map(songObj => {
return (
<View style={styles.resultsContainer}> /// Its written that the erorr in this line
<TouchableOpacity onPress={this.GetListViewItem.bind(this, songObj.Song_Name)}>
<Text style={{ fontSize: 16 }} key={songObj.Song_ID}>
{songObj.Song_Name}</Text>
<Image source={{ uri: songObj.Image }} style={styles.img} />
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</View>
);
}
I don't understand where to put the key and/or what does it mean, I tried so many times but it didn't went well.
If more details is needed please tell me and I'll insert the right code.
You should add the key onto the outermost component inside the map. In your case, this is the View. Try this:
return (
<View>
<ScrollView>
{musicList.map(songObj => {
return (
<View style={styles.resultsContainer} key={songObj.Song_ID}>
<TouchableOpacity onPress={this.GetListViewItem.bind(this, songObj.Song_Name)}>
<Text style={{ fontSize: 16 }}>
{songObj.Song_Name}</Text>
<Image source={{ uri: songObj.Image }} style={styles.img} />
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</View>
);
}
Adding the key prop lets react optimize rendering which is why it recommends you add it. Read the docs for more info.

How to handle onPress function react

I am using react native with NativeBase components, and I am having a problem calling my _doStuff function. I tried to call
onPress={this._doStuff.bind(this)}
but keep receiving
Cannot read properly 'doStuff' of undefined
_doStuff(){
console.log('Hi');
}
_getList() {
return this.state.listData.map(function(data, i){
return(
<View key={i}>
<ListItem style={styles.listItemContain}>
<Button transparent onPress={this._doStuff.bind(this)}>
<View>
<Thumbnail source={{uri: data.icon}} style={styles.thumbnailStyle}/>
<Text style={styles.title}>{data.name}</Text>
<Text note style={styles.text}>{data.vicinity}</Text>
</View>
</Button>
</ListItem>
</View>
);
});
this context is lost inside the .map loop. if you are using ES6, try to use fat arrow functions as shown below.
_getList() {
return this.state.listData.map((data, i) => {
return(
<View key={i}>
<ListItem style={styles.listItemContain}>
<Button transparent onPress={this._doStuff.bind(this)}>
<View>
<Thumbnail source={{uri: data.icon}} style={styles.thumbnailStyle}/>
<Text style={styles.title}>{data.name}</Text>
<Text note style={styles.text}>{data.vicinity}</Text>
</View>
</Button>
</ListItem>
</View>
);
});
if you cant use ES6 on your project due to various reasons use alternative approach(old school) as shown below...
_getList() {
return this.state.listData.map(function(data, i){
var that = this;
return(
<View key={i}>
<ListItem style={styles.listItemContain}>
<Button transparent onPress={that._doStuff.bind(that)}>
<View>
<Thumbnail source={{uri: data.icon}} style={styles.thumbnailStyle}/>
<Text style={styles.title}>{data.name}</Text>
<Text note style={styles.text}>{data.vicinity}</Text>
</View>
</Button>
</ListItem>
</View>
);
});
I would make a wager that the context of your _getList function does not have the context of the React Component that you are thinking. If you are using ES6 classes and would like to get autobinding of the components context I would suggest using autobind-decorator. If you decide to go that route here is a nice tutorial on setting it up.
Otherwise make sure that when you call _getList make sure to call it with either .call or .bind.
For example:
// if you are calling the function directly
this._getList().call(this)
or
// if you are passing the function off for another function to execute it
this._getList.bind(this)

React Native : set id to a component and get this component's id

I am developing my first React Native app and I am trying to set an id to a component so that I can determine this view when pressing on it and displaying data according to the component's id
This is what I tried so far:
renderRow(rowData, sectionID, rowID){
var past_matches_circles =[];
for(var i=0; i<isPast; i++){
past_matches_circles.push(
<TouchableOpacity id={i} key = {i} collapsable={false} style={styles.small_circle} onPress={()=>this.pressOnCircle(rowData[`${i}`].MatchID)}>
</TouchableOpacity>
);
}
return (
<View>
<View style={{flexDirection:'row'}}>
{past_matches_circles}
</View>
<View style={{flexDirection:'row'}}>
<Image style={{width:100, height:100, margin:5}} source={{uri:'http://facebook.github.io/react/img/logo_og.png'}}/>
<View style={{justifyContent:'center', flex:1}}>
<Text> {rowData[0].MatchDate} </Text>
<Text> {rowData[0].HomeTeam} VS {rowData[0].AwayTeam} </Text>
</View>
</View>
</View>
);
}
pressOnCircle(i){
ToastAndroid.show('key ' + i, ToastAndroid.SHORT);
}
but unfortunately the iterator i value is always equal to its last value inside the loop regardless which view I am pressing on.
Can anyone help me getting component's id?
After several days, finally I solved this problem. And I'll post it for who will come to this question.
I was pushing the views into my array without returning so the value of i is always the same.
so that what I did:
renderCircle(id) {
return <TouchableOpacity key={id} style={styles.small_circle} onPress={() => this.pressOnCircle(id)}>
</TouchableOpacity>;
}
renderRow(rowData, sectionID, rowID){
var past_matches_circles =[];
for(var i=0; i<isPast; i++){
past_matches_circles.push(
this.renderCircle(i)
);
}
var { page, animationsAreEnabled } = this.state;
return (
<View>
<View style={{flexDirection:'row'}}>
{past_matches_circles}
</View>
<View style={{flexDirection:'row'}}>
<Image style={{width:100, height:100, margin:5}} source={{uri:'http://facebook.github.io/react/img/logo_og.png'}}/>
<View style={{justifyContent:'center', flex:1}}>
<Text> {rowData[0].MatchDate} </Text>
<Text> {rowData[0].HomeTeam} VS {rowData[0].AwayTeam} </Text>
</View>
</View>
</View>
);
}
Hope that will help.
You can use .bind to create a new function that closes over the value of i. This isn't the best for performance as you're creating a new function each time.
onPress={ this.pressOnCircle.bind(this, i) }>
Also, you might need to do something like
this.pressOnCircle = this.pressOnCircle.bind(this);
In the constructor to get the proper this context in the handler.

react native can't assign simple variable

I have the weirdest (i'm sure it's simple) bug with react native.
I am using Parse for the backend. getting a parse object and trying to render a react object from it's attributes. simple.
renderRow(rowData, sectionID, rowID) {
console.log(rowData);
var data = rowData._serverData;
var photo_url = rowData._serverData.photo_url;
return (
<TouchableHighlight onPress={() => this.rowPressed(rowData.guid)}
underlayColor='#dddddd'>
<View>
<View style={styles.rowContainer}>
<Image style={styles.thumb} source={{ uri: photo_url }} />
<View style={styles.textContainer}>
<Text style={styles.title}>{rowData._serverData.badge}</Text>
<Text style={styles.description}
numberOfLines={2}>{rowData._serverData.description}</Text>
</View>
</View>
<View style={styles.separator}/>
</View>
</TouchableHighlight>
);
}
I'm getting cannot read property 'photo_url' of undefined for this row
var photo_url = rowData._serverData.photo_url;.
this thing is , the data is there, I have made sure with the chrome debugger.
turns out there is something weird with Parse.
doing this:
rowData.attributes.photo_url
solved it. I have to say i'm not quite sure why.

Categories

Resources