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

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/

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>
);
);

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.

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)

React Native with Redux- Problems updating state correctly

I'm trying to upload images that I've base64 encoded but it doesn't seem to save the state to the app so I can upload the images to my server. The state only seems to save within the function and not to the entire component. Any suggestions as to what I'm doing wrong?
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.state = {
selected: image
};
console.log(this.state)
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }}>
<TouchableOpacity style={ styles.button } onPress={ this._addImage.bind( this ) }>
<Text>Add Image</Text>
</TouchableOpacity>
<TouchableOpacity style={ styles.button } onPress={this._uploadImage} >
<Text>Upload Image</Text>
</TouchableOpacity>
</View>
<ScrollView style={styles.container}>
<View style={styles.imageGrid}>
{ this.state.images.map((image) => {
return (
<TouchableHighlight onPress={this._selectImage.bind(null, image.uri)}>
<Image key={ _generateUUID() } style={styles.image} source={{ uri: image.uri }} />
</TouchableHighlight>
);
})
}
</View>
</ScrollView>
</View>
);
}
};
First, this-bind your _selectImage-method in constructor. Then use "setState" instead of this.state = {...}
You need only once to create the state object, best in constructor. Use then setState instead for further modifications.
constructor(props) {
super(props);
this.state = {selected: null};
this._selectImage = this._selectImage.bind(this);
}
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.setState({
selected: image
});
console.log(this.state)
});
}

React Native Navigator set title dynamically iOS

var MainPage = React.createClass({
onPress() {
this.props.navigator.push({
title: 'Home Page',
component: Homepage
});
},
render() {
return (
<View style={[styles.scene, {backgroundColor: '#DAF6FF'}]}>
<TouchableHighlight
style={styles.menubutton}
onPress={this.onPress}>
<Text style={styles.white}>This page</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.menubutton}
onPress={this.onPress}>
<Text style={styles.white}>That page</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.menubutton}
onPress={this.onPress}>
<Text style={styles.white}>Another page</Text>
</TouchableHighlight>
</View>
);
}
});
How can I send a variable with this.onPress to set the navigator title dynamically? ie if I press 'This page' it would set the title to 'This page' in the onPress function. Also it would be useful to set the component dynamically.
Other than creating separate functions for every menu item there doesn't seem to be any obvious way to achieve this. I've tried various things and searched to no avail.
You can pass the title as a paramater to the function:
<TouchableHighlight
style={styles.menubutton}
onPress={ () => this.onPress('Another page') }>
<Text style={styles.white}>Another page</Text>
</TouchableHighlight>
Then, assign it in the navigator function:
onPress(title) {
this.props.navigator.push({
title: title,
component: Homepage
});
}
If you wanted to dynamically set the component, you could take it one step further and use a switch statement:
onPress(title) {
switch(title) {
case 'Another page':
var component = AnotherPage;
break;
}
this.props.navigator.push({
title: title,
component: component
});
}

Resources