React-Native. TouchableOpacity works only when tap with 2 fingers - ios

I'm running my app via React-Native and native-base and I got some problems with component TouchableOpacity.
When I'm writing my component like
<TouchableOpacity onPress={() => {this.onPress()}}>
<Text>Some text</Text>
</TouchableOpacity
It works perfect, when I tap with 1 finger
But when I'm running like this - My Code:
renderList () {
return (
<List>
{this.state.data.map( ( restaurant, index ) => {
return (
<TouchableOpacity onPress={() => {
this.onPress();
}} key={index}>
<View style={styles.example}>
<ListItem>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</ListItem>
</View>
</TouchableOpacity>
);
} )}
</List>
);
}
It is ignoring 1 tap, twice tap etc, it is only working when I tap with 2 fingers. Didn't find any info about this problem. May be some one know how to solve this?
Thanks
Added FullCode:
import React, { Component } from 'react';
import {
Container,
Button,
Header,
Left,
Icon,
Body,
Right,
Text,
Content,
List,
ListItem,
Thumbnail
} from 'native-base';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
export default class Restaurants extends Component {
constructor ( props ) {
super( props );
this.state = {
data: this.props.data
};
}
onPress () {
console.log( 'Hello' );
}
renderList () {
return (
<List>
{this.state.data.map( ( restaurant, index ) => {
return (
<TouchableOpacity onPress={() => {
this.onPress();
}} key={index}>
<View style={styles.example}>
<ListItem>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</ListItem>
</View>
</TouchableOpacity>
);
} )}
</List>
);
}
render () {
return (
<Container>
<Header style={styles.header}>
<Left>
<Button transparent>
<Icon style={styles.header_icon} name="arrow-back"/>
</Button>
</Left>
<Body>
<Text>Ресторанны</Text>
</Body>
<Right>
<Button transparent>
<Icon style={styles.header_icon} name="restaurant"/>
</Button>
</Right>
</Header>
<Content>
{this.renderList()}
</Content>
</Container>
);
}
}
const styles = StyleSheet.create( {
header: {
backgroundColor: '#606dff'
},
header_icon: {
color: 'black'
},
example: {
backgroundColor: 'red'
}
} );

As we spoken, I'll post it here so it's better to read and copy the code.
Try this:
renderList() {
return (
<List>
{
this.state.data.map( ( restaurant, index ) => {
return (
<ListItem>
<TouchableOpacity
onPress={() => {
this.onPress();
}}
key={index}
>
<View style={styles.example}>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</View>
</TouchableOpacity>
</ListItem>
);
});
}
</List>
);
}
I swapped <ListItem> and <TouchableOpacity>
There might be any conflict the way you wrote.
Let me know if it worked.

Related

FlatList item click is not rendering this

export default class HistoryScreen extends BaseScreen {
constructor(props){
super(props);
this.state = {
mainListData:[],
listData:[],
searchText:'',
};
}
listRowPressed(item) {
this.props.navigation.navigate('Details', {
checkin: item.data
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex:1, backgroundColor: '#FFF'}}>
<FlatList
data={this.state.listData}
renderItem={({item}) => <ListComp data={item} />}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
}
const ListComp = item => (
<TouchableOpacity onPress={() => this.listRowPressed(item)
}>
<View style={styles.row}>
</View>
</TouchableOpacity>
);
I am displaying data in FlatList, however clicking on item gives me this4. listRowPressed is undefined, I tried binding the function too but didn't work. What is wrong in the code?
You have to pass listRowPressed in your ListComp component. Your whole code should be like this :
export default class HistoryScreen extends BaseScreen {
constructor(props) {
super(props);
this.state = {
mainListData: [],
listData: [],
searchText: '',
};
}
listRowPressed = (item) => {
this.props.navigation.navigate('Details', {
checkin: item.data
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, backgroundColor: '#FFF' }}>
<FlatList
data={this.state.listData}
renderItem={({ item }) => <ListComp data={item} listRowPressed={this.listRowPressed} />}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
}
const ListComp = (props) => (
<TouchableOpacity
onPress={() => props.listRowPressed(props.item)}
>
<View style={styles.row}>
{/* Do whatever with props.item here */}
</View>
</TouchableOpacity>
);
Also note that I have converted your method listRowPressed simple function to arrow function.
Try this
<FlatList
data={this.state.listData}
renderItem={this.listComp}
keyExtractor={(item, index) => index.toString()}
/>
listComp = ({item}) => (
return(
<TouchableOpacity onPress={() => this.listRowPressed(item)} >
<View style={styles.row}>
</View>
</TouchableOpacity>
);
);

Unable to display fetched data in react native firebase using this.state.data.map()

I have been battling with the display of database item on my page using this.state.noteArray.map(val, key). I intend to display each value with a delete button to remove it from the page.
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity
} from 'react-native';
import firebase from 'firebase';
// Initialize Firebase
const config = {
apiKey: "XXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXXXXXXXXXXXXXX",
databaseURL: "XXXXXXXXXXXXXXXXXXXXXXXX",
projectId: "XXXXXXXXXXXXXXXXXXXXXX",
storageBucket: "",
messagingSenderId: "XXXXXXXXXXXXXXXXXXXX"
};
firebase.initializeApp(config);
export default class Main extends Component {
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
};
this.addNote = this.addNote.bind(this);
}
componentDidMount(){
firebase.database()
.ref()
.child("todo")
.once("value", snapshot => {
const data = snapshot.val()
if (snapshot.val()){
const initNoteArray = [];
Object
.keys(data)
.forEach(noteText => initNoteArray.push(data[noteText]));
this.setState({
noteArray: initNoteArray
});
}
});
firebase.database()
.ref()
.child("todo")
.on("child_added", snapshot => {
const data = snapshot.val();
if (data){
this.setState(prevState => ({
noteArray: [data, ...prevState.noteArray]
}))
console.log(this.state.noteArray);
}
})
}
addNote(){
// firebase function here to send to the database
if (!this.state.noteText) return;
var d = new Date();
const newNote = firebase.database().ref()
.child("todo")
.push ({
'date':d.getFullYear()+
"/"+(d.getMonth()+1) +
"/"+ d.getDate(),
'note': this.state.noteText
});
newNote.set(this.state.noteText, () => this.setState({noteText: ''}))
}
render() {
let notes = this.state.noteArray.map((val, key)=>{
return
(<View key={key} keyval={key} val={val} style={styles.note}>
<Text style={styles.noteText}>{this.state.val.date}</Text>
<Text style={styles.noteText}>{this.state.val.note}</Text>
<TouchableOpacity onPress={this.state.deleteMethod} style={styles.noteDelete}>
<Text deleteMethod={()=>this.deleteNote(key)} style={styles.noteDeleteText}>D</Text>
</TouchableOpacity>
</View>)
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);
}
deleteNote(key){
this.state.noteArray.splice(key, 1);
this.setState({noteArray: this.state.noteArray});
}
}
There is no warning or error, but it is not displaying anything. I will appreciate if there is any help and inline comment to understand the process for the next time, I am a newbie, trying to master the code for future similar projects. All I care to know is the basic understanding of the CRUD and search using React native firebase. Thank you so much
If I correctly understand you need a proper way to display your data. Since noteArray is an array, there's nothing easier than a FlatList, which is scrollable by itself.
So, in your render method:
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.noteArray} // Here is where you pass your array of data
renderItem={this.renderItem} // Here is how to display each item of your data array
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
/>
</View>
);
}
Where:
renderHeader = () => {
return (
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
)
}
renderFooter = () => {
return (
<View>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
)
}
renderItem = ({ item, index }) => {
return (
<View key={index} style={styles.note}>
<Text style={styles.noteText}>{item.date}</Text>
<Text style={styles.noteText}>{item.note}</Text>
<TouchableOpacity onPress={this.state.deleteMethod} style={styles.noteDelete}>
<Text deleteMethod={()=>this.deleteNote(index)} style={styles.noteDeleteText}>D</Text>
</TouchableOpacity>
</View>
)
}
Thanks for your support. I have reviewed my code and it is working perfectly as I want. I will love to post it here in case someone else needs to work or learn about it. I used array.map() function to iterate over the items.
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity
} from 'react-native';
import Note from './Note';
import firebase from 'firebase';
// Initialize Firebase
const config = {
apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXXXXXXXXXXXXXX",
databaseURL: "XXXXXXXXXXXXXXXXXXXXXXXX",
projectId: "XXXXXXXXXXXXXXXXXXXXXXXXX",
storageBucket: "",
messagingSenderId: "XXXXXXXXXXXXXXXX"
};
firebase.initializeApp(config);
export default class Main extends Component {
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
};
this.addNote = this.addNote.bind(this);
}
componentDidMount(){
firebase.database()
.ref()
.child("todo")
.once("value", snapshot => {
const data = snapshot.val()
if (snapshot.val()){
const initNoteArray = [];
Object
.keys(data)
.forEach(noteText => initNoteArray.push(data[noteText]));
this.setState({
noteArray: initNoteArray
});
}
});
firebase.database()
.ref()
.child("todo")
.on("child_added", snapshot => {
const data = snapshot.val();
if (data){
this.setState(prevState => ({
noteArray: [data, ...prevState.noteArray]
}))
console.log(this.state.noteArray);
}
})
}
addNote(){
// firebase function here to send to the database
if (!this.state.noteText) return;
var d = new Date();
const newNote = firebase.database().ref()
.child("todo")
.push ();
newNote.set({
'date':d.getFullYear()+
"/"+(d.getMonth()+1) +
"/"+ d.getDate(),
'note': this.state.noteText
});
this.setState({noteText:''});
}
render() {
let notes = this.state.noteArray.map((val, key)=>{
return <Note key={key} keyval={key} val={val}
deleteMethod={()=>this.deleteNote(key)}/>
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);
}
deleteNote(key){
this.state.noteArray.splice(key, 1);
this.setState({noteArray: this.state.noteArray});
}
}
I have another .js component named Note.js for display template. This was included in the Main.js and was reference just after the render.
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
export default class Note extends Component {
render() {
return (
<View key={this.props.keyval} style={styles.note}>
<Text style={styles.noteText}>{this.props.val.date}</Text>
<Text style={styles.noteText}>{this.props.val.note}</Text>
<TouchableOpacity onPress={this.props.deleteMethod} style={styles.noteDelete}>
<Text style={styles.noteDeleteText}>D</Text>
</TouchableOpacity>
</View>
);
}
}

React Native Element Type is invalid Error While using ActivityIndicatorIOS

I have begun to develop a book-searching application using React and Google Books API. However, I have run into an error where my simulator reads:
Element Type is invalid: expected a string (for built-in components) or
a class/function (for composite components) but got: undefined. Check
the render method of 'BookList'.
Given that I am fairly new to React, I was hoping someone might be able to point out the error(s) in my code below. I have noted the place where I think there may be an error. Thanks!
class BookList extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
})
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch(REQUEST_URL[0])
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.items),
isLoading: false
});
})
.done();
}
render() {
if (this.state.isLoading) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderBook.bind(this)}
style={styles.listView}
/>
);
}
// *** adding this function (and using it) began to cause issues ****
renderLoadingView() {
return (
<View style={styles.loading}>
<ActivityIndicatorIOS
size='large'/>
<Text>
Loading books...
</Text>
</View>
);
}
renderBook(book) {
return (
<TouchableHighlight>
<View>
<View style={styles.container}>
<Image
source={{uri: book.volumeInfo.imageLinks.thumbnail}}
style={styles.thumbnail} />
<View style={styles.rightContainer}>
<Text style={styles.title}>{book.volumeInfo.title}</Text>
<Text style={styles.author}>{book.volumeInfo.authors}</Text>
<Text style={styles.price}>{'Lowest Available Price: ' + book.volumeInfo.price}</Text>
</View>
</View>
<View style={styles.separator} />
</View>
</TouchableHighlight>
);
}
}
var REQUEST_URL = ['https://www.googleapis.com/books/v1/volumes?q=subject:fiction'];
ActivityIndicatorIOS is depreciated use ActivityIndicator instead.

How did I use the push() function in NavigatorIOS?

I want to Push to a new Component by the function push() in NavigatorIOS. It's like following:
renderRow(rowData, sectionID, rowID) {
var imgSource = IMAGE_URLS[rowID];
return (
<TouchableHighlight onPress = {() => {
this.props.navigator.push({
title: 'test',
component: example,
});
}}>
<View>
<View style={styles.row}>
<Image
source={imgSource}
style={styles.thum}
/>
<Text style={styles.text}>
{rowData}
</Text>
</View>
</View>
</TouchableHighlight>
);
}
But it will get a error when I click the TouchableHighlight.
I refered these two questions(1 and 2) before this. And the complete code is in this link
this is not binded to the class inside of renderRow().
You have to bind this either in the constructor:
this.renderRow = this.renderRow.bind(this);
or inside the render method:
render() {
var navStatusBarConfig = {
style: 'light-content',
}
return (
<View style={{ flex: 1, backgroundColor: '#F5FCFF'}}>
<View styles={styles.nav}></View>
<ListView
automaticallyAdjustContentInsets={false}
contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
pageSize={4}
renderRow={this.renderRow.bind(this)}
/>
</View>
);
}
}
As to why, here is the reason :
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
And a more complete blog about how to bind this [there are many, blogs and ways to bind this]) :
http://blog.andrewray.me/react-es6-autobinding-and-createclass/

Presenting & Closing a modal

So I have an Initial Screen below which allows you to click on a button and present a modal screen:
import SettingsScreen from './SettingsScreen';
...
export default class InitialScreen extends Component {
constructor(props) {
super(props);
this.state = {modalVisible: false};
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View>
<NavigationBar
title={{ title: 'Initial Screen', tintColor: 'white', }}
leftButton={
<TouchableOpacity onPress={() => {
this.setModalVisible(!this.state.modalVisible)
}}>
<Image style={styles.leftButton} source={require('./../img/settings.png')} />
</TouchableOpacity>
}
rightButton={{ title: 'Forward', tintColor: 'white' }}
style={{ backgroundColor: '#2196F3', }}
statusBar={{ tintColor: '#1976D2', style: 'light-content' }}
/>
<Modal
animationType={"slide"}
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {alert("Modal has been closed.")}}
>
<SettingsScreen />
</Modal>
</View>
);
}
}
It works, but now in my Modal screen I have a button which allows you to dismiss the modal:
import ...
export default class ModalScreen extends Component {
render() {
return (
<View>
<TouchableOpacity onPress={() => {
this.props.setModalVisible(!this.state.modalVisible)
}}>
<Image source={require('./../img/close.png')} />
</TouchableOpacity>
</View>
);
}
}
But it's giving me an error saying this.props.setModalVisible(!this.state.modalVisible) is not a function.
How would I dismiss the modal within the ModalScreen?
Thank you.
you should pass the setModalVisible() function to the modal component
Initial Component:
<ModalComponent closeModal={this.setModalVisible} />
and on ModalComponent call it like this:
<TouchableOpacity onPress={() => {
this.props.closeModal(false)
}}>
<Image source={require('./../img/close.png')} />
</TouchableOpacity>
For custom functions in react native use ES6 style:
setModalVisible = (visible) => {
this.setState({modalVisible: visible});
}
And the code should be: this.setModalVisible(!this.state.modalVisible)

Resources