Issue on loading component with TabBarIOS through Navigator - react-native

I've been trying to load up a component through RenderScene function under Navigator. If the route doesn't contain any corresponding object based on the route.object I would fire up the navigator to return the view with the tabBarIOS, the code on the second snippet is how the TabView looks.
render: function() {
var initialRoute = {login: true};
return (
<Navigator
ref="navigator"
style={styles.container}
configureScene={(route) => {
if(Platform.OS === 'android') {
return Navigator.SceneConfigs.FloatFromBottomAndroid;
}
//
else {
return Navigator.SceneConfigs.FloatFromBottom;
}
}}
initialRoute={initialRoute}
renderScene={this.renderScene}
navigationBar={
<Navigator.NavigationBar
routeMapper={NavigationBarRouteMapper}
style={styles.navBar}
/>
}
/>
);
},
renderScene: function(route, navigator) {
if(route.login) {
return (
<LoginScreen
navigator={navigator}
onLogin={route.callback}
/>
);
}
return (
<HomeTab navigator={navigator}/>
);
}
The component with the tabs and supposedly the homepage after logging in is this
import React, { Component } from 'react';
import {
AppRegistry,
TabBarIOS,
StyleSheet
} from 'react-native';
var Welcome = require('./welcome.ios');
var More = require('./more.ios');
export default class TabBarIOSSpike extends Component {
constructor(props) {
super(props);
this.state = {
selectedTab: 'welcome'
};
}
render() {
return (
<TabBarIOS selectedTab={this.state.selectedTab}>
<TabBarIOS.Item
selected={this.state.selectedTab === 'welcome'}
icon={{uri:'featured'}}
onPress={() => {
this.setState({
selectedTab: 'welcome',
});
}}>
<Welcome/>
</TabBarIOS.Item>
<TabBarIOS.Item
selected={this.state.selectedTab === 'more'}
icon={{uri:'contacts'}}
onPress={() => {
this.setState({
selectedTab: 'more',
});
}}>
<More/>
</TabBarIOS.Item>
</TabBarIOS>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
I've been getting the weird error below. By the way, I've tested loading the hometab as the homepage and it works fine, only in this case if its wired up from the navigator that it occurs.
Unhandled JS Exception: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `Navigator`.

Related

Element type is invalid: expected a string with FlatList

Iam new to react-native, and are playing around with UI Kitten (https://akveo.github.io/react-native-ui-kitten/)
It has a default ChatListScreenBase that renders a list. It looks like this:
import React, {Component} from 'react';
import {
StyleSheet,
View,
ListView
} from 'react-native';
import ThemeService from '../util/ThemeService';
import api from '../util/ApiMock';
export default class ChatListScreenBase extends Component {
constructor(props) {
super(props);
let ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
let data = api.getUserMsgList(api.userId);
this.state = {
dataSource: ds.cloneWithRows(data)
};
}
render() {
let Header = ThemeService.getChatListHeaderComponent();
return (
<View style={styles.container}>
<Header/>
<ListView
style={styles.list}
automaticallyAdjustContentInsets={false}
dataSource={this.state.dataSource}
renderRow={(row) => this._renderMsgItem(row)}
/>
</View>
)
}
_renderMsgItem(msg) {
let user = api.getUserInfo(msg.from);
let ChatItem = ThemeService.getChatItemComponent();
msg.text = msg.text.length > 25 ? msg.text.substring(0,23)+'...' : msg.text;
return (
<ChatItem
user={user}
message={msg}
onClick={(user) => this._openChat(user)}
/>
);
}
_openChat(user) {
this.props.navigator.push({
screen: ThemeService.getChatScreen(true),
passProps: {
userId: user.id
}
});
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
},
list: {
paddingTop: 10
},
});
I would like to substitute the data this screen renders, with my own code, like this:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
FlatList
} from 'react-native';
import ajax from '../util/ApiMock';
export class ChatListScreenBase extends Component {
constructor(props) {
super(props);
this.state = {
themeIndex: ThemeService.getCurrentThemeIndex()
}
}
state = {
data: []
}
async componentDidMount() {
const data = await ajax.getDataTest();
this.setState({data});
}
render() {
return (
<View style={styles.container} >
<Text style={styles.h2text}>
Black Order
</Text>
<FlatList
data={this.state.data}
showsVerticalScrollIndicator={false}
renderItem={({item}) =>
<View style={styles.flatview}>
<Text style={styles.name}>{item.title}</Text>
</View>
}
keyExtractor={item => item.title}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 50,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
h2text: {
marginTop: 10,
fontFamily: 'Helvetica',
fontSize: 36,
fontWeight: 'bold',
},
flatview: {
justifyContent: 'center',
paddingTop: 30,
borderRadius: 2,
},
name: {
fontFamily: 'Verdana',
fontSize: 18
},
email: {
color: 'red'
}
});
When I do this, I keep getting this error:
"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 ChatListScreenBase."
I think that the problem is with the <FlatList>, but I'am not sure what type its expecting?
When I call the webservice it returns:
{"users":[{"_id":"5d0fcd8fe1dbfd7c23424e09","title":"180710","type":1,"published":"5"},{"_id":"5d0fcd8fe1dbfd7c23424e0a","title":"180705","type":3,"publiched":"5"},{"_id":"5d0fcd8fe1dbfd7c23424e0b","title":"Mr.
Nick","type":2,"publiched":"5"}]}
Kind regards.
For the looks of your API response you are setting data as object with key users and then trying to loop over it.
Instead update componentDidmount:
async componentDidMount() {
const resp = await ajax.getDataTest();
this.setState({ data: resp.users });
}

How to fix error Element type is invalid expected a string?

I have an expo application that shows me 3 tabs and when I go to the 'Camera'
tab I always get an error. I tried almost all solutions but this doesnt wan't to work.
The error is : "Invariant Violation: Element type is invalid expected a string (for build-in components) or a class/function (for composite elements) but got undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of "CameraExample"
Here is the tree :
!https://nsa40.casimages.com/img/2019/01/24/190124124747913567.png
here is my file index.js :
import { TabNavigator } from 'react-navigation';
import LoginForm from './LoginForm';
import SignUpForm from './SignUpForm';
import CameraExample from './CameraExample';
const routeConfigs = {
Login: {
screen: LoginForm,
},
SignUp: {
screen: SignUpForm,
},
Camera: {
screen: CameraExample,
},
};
const tabBarOptions = {
tabBarOptions: {
activeTintColor: '#88cc88',
inactiveTintColor: '#aaaaaa',
showIcon: true,
scrollEnabled: false,
indicatorStyle: {
display: 'none',
},
style: {
backgroundColor: '#ffffff',
},
},
tabBarPosition: 'bottom',
};
export default TabNavigator(routeConfigs, tabBarOptions);
CameraExample/Component.js
import { Camera, Permissions } from 'expo';
import React, { Text, View, Component } from 'react';
class CameraExample extends Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
async componentDidMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
render() {
const { hasCameraPermission, type } = this.state;
if (hasCameraPermission === null) {
return <View />;
} if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={type}>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}
>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type: type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}
>
<Text
style={{ fontSize: 18, marginBottom: 10, color: 'white' }}
>
{' '}
Flip
{' '}
</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
module.exports = CameraExample;
and CameraExample/index.js
export { default } from './Component';
I think it needs to be written this way
CameraExample/index.js
import Component from './Component'
export default Component
OR
module.exports = require('./Component')

How to re render a screen and it all compoent after moving from one tab to another and back to first tab?

I am trying get re render a screen every time the user presses a tab or moving from one tab to another and then to first tab. I also placed a custom header in the screen. Same header on all the other tabs too getting some state from Asynchronous storage but it is also not refreshing once the screen has loading. I am using react navigation. Is there any method in navigation which will be called whenever tab is focused.
const AppStack = createBottomTabNavigator(
{
Search: SearchScreen,
Saved: SavedScreen,
Explore: ExploreStack,
Offers: OffersScreen,
Profile: ProfileScreen,
},
{
initialRouteName: 'Explore',
navigationOptions: ({navigation})=>({
tabBarIcon: ({focused, tintColor})=>{
const { routeName } = navigation.state;
let iconName, iconSize;
switch(routeName) {
case "Search":
iconName = `ios-search${focused ? '' : '-outline'}`;
break;
case "Saved":
iconName = `ios-heart${focused ? '' : '-outline'}`;
break;
case "Explore":
iconName = `ios-navigate${focused ? '' : '-outline'}`;
break;
case "Offers":
iconName = `ios-pricetag${focused ? '' : '-outline'}`;
break;
case "Profile":
iconName = `ios-person${focused ? '' : '-outline'}`;
break;
default:
break;
}
return <Icon name={iconName} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'black',
inactiveTintColor: 'grey',
activeBackgroundColor: '#abaf9b',
labelStyle: {
fontSize: 15,
},
// style for tabbar
style: {
backgroundColor: '#ffffff',
height: 60,
justifyContent: 'space-around',
alignContent: 'center',
alignItems: 'center',
},
// style for tab
tabStyle: {
paddingTop: 7,
paddingBottom: 7
}
},
}
)
This is one of the tab. Other tabs a very similar using same component but the different apis.
import React, { Component } from 'react';
import { View, Image, ActivityIndicator, TouchableWithoutFeedback, TouchableHighlight, AsyncStorage } from 'react-native';
import HeaderComponent from '../components/Header';
import SomeComponent from '../components/Some';
import { Container, Content, Icon, Spinner} from 'native-base';
class FirstScreen extends Component{
constructor(props){
super(props)
this.state = {
somelist: [],
name: '',
userId: '',
isloading: true,
location: ''
};
this.getUser();
}
componentDidMount(){
this.getLocation();
}
getLocation = async() => {
const result = await AsyncStorage.getItem('location');
console.log("Location " +result)
this.setState({location: result});
}
getUser = async() => {
const result = await AsyncStorage.getItem('user');
const data = JSON.parse(result);
console.log("data : "+data)
this.setState({name: data.name, userId: data.userId})
}
componentWillMount(){
console.log("Component will mount")
//For demo
fetch('http://someapi.co/api/listing')
.then(response => response.json())
.then(data => {
this.setState({ somelist: data, isloading: false }, function(){console.log(this.state.somelist, this.state.isloading)})
})
.catch(function(error){
console.log("Error : "+error);
});
//console.log(this.state.barlist);
}
renderComponent(){
if(this.state.isloading == true){
return (
<View style={{ flex: 1, justifyContent: 'center', height: 300 }}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
);
}
return this.state.somelist.map( user=>
<SomeComponent key={user.id}
onPress={()=>this.props.navigation.navigate('OtherScreen', {'Id': user.id, 'userId': this.state.userId})}
image={user.image[0].imageName}
/>
);
}
render(){
console.log(this.state.userId)
return (
<Container>
<HeaderComponent
profilePress={()=>this.props.navigation.navigate('Profile')}
seachPress={()=>this.props.navigation.navigate('SearchSetting')}
// location={this.state.location}
/>
<TouchableHighlight
style={{position: 'absolute', bottom: 20, zIndex:999999, right: 20 }}
onPress={()=>this.props.navigation.navigate('Map')}
>
<Image source={require('../images/navigation_icon.png')} style={{height: 50, width: 50}}/>
</TouchableHighlight>
<Content>
<View style={{padding: 0, margin: 0}}>
{this.renderComponent()}
</View>
</Content>
</Container>
);
}
}
export { SomeScreen };
You can access the event listeners in react-navigation as mentioned here
// call when the screen is focused
componentDidMount () {
this._onFocusListener = this.props.navigation.addListener('didFocus', (payload) => {
// refresh the component here
// or update based on your requirements
});
}
Please refer the link: https://reactnavigation.org/docs/en/navigation-prop.html#addlistener-subscribe-to-updates-to-navigation-lifecycle
There are 2 different ways I found below,
// call when the screen is focused
componentDidMount () {
this._navListener = this.props.navigation.addListener('didFocus', (payload) => {
// update based on your requirements
});
}
OR
import { NavigationEvents } from "react-navigation";
...
class HomeScreen extends React.Component {
render() {
return (
<View>
<NavigationEvents
onWillFocus={() => {
// update based on your requirements!
}}
/>
<Text>Home</Text>
</View>
);
}
}

React-Native Navigator Android Error

Native app development
This is what I tried
File: index.android.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Navigator,
TouchableHighlight,
Text,
View
} from 'react-native';
var Loader = require('./app/components/Loader');
var Login = require('./app/components/Login');
export default class Demo extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Navigator>
initialRoute = {{
id:'Loader',
}}
renderScene = {(route, navigator) => {
_navigator = navigator;
switch (route.id){
case 'Loader':
return (<Loader navigator={navigator} route={route} title="Loader"/>);
case 'Login':
return (<Login navigator={navigator} route={route} title="Login"/>);
}
}
}
</Navigator>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('Demo', () => Demo);
My Loader Component :
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image
} from 'react-native'
class Loader extends Component{
constructor(props) {
super(props);
this.state = {
id: 'Loader'
}
}
render(){
return(
<View style={styles.container}>
<Image source={require('../assets/img/ace-logo-white-01.png')} style={styles.logo}/>
<Text style={styles.loadingText}>Loading...</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'red'
},
logo: {
height: 30,
width: 50
},
loadingText: {
flex:1,
fontSize: 25,
paddingTop: 20,
color: 'white'
}
});
module.exports = Loader;
when I run the app I am getting error undefined is not a funtion(evaluating 'this.props.renderScene(route,this)')
I have tried this by watching some tutorials on Youtube but I can't find the answer to my problem.
What I want to do is when the app is launched the Loader component I made should load and then from loader component I redirect user to the Login componet but currently I am not able to load any component as it loads with the error I stated above.
Here is a sample code for you:
render() {
return (
<Navigator
initialRoute={{ id: 'Sample', name: 'Index' }}
renderScene={this.renderScene.bind(this)}
configureScene={(route, routeStack) => Navigator.SceneConfigs.FloatFromRight}
/>
); }
renderScene = (route, navigator) => {
if (route.id === 'Sample') {
return (
<Sample
navigator={navigator}
/>
);
}
}
You may have made some syntax mistakes with the code given by #JainZz. Try this
import Loader from './app/components/Loader'
export default class Demo extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Navigator
initialRoute={{ id: 'Loader', name: 'Loader' }}
renderScene={this.renderScene.bind(this)}
configureScene={(route, routeStack) => Navigator.SceneConfigs.FloatFromRight}
/>
);
}
renderScene = (route, navigator) => {
if (route.id === 'Loader') {
return (
<Loader
navigator={navigator}
/>
);
}
}
}

How to pass data from one screen to other screen in React Native

1. index.android.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
View
} from 'react-native';
import Button from 'react-native-button';
class AwesomeProject extends Component {
constructor(props){
super(props)
this.state = {
username: '',
email: '',
address: '',
mobileNumber: ''
}
render() {
return (
<View style={styles.container}>
<TextInput
ref={component => this.txt_input_name = component}
style={styles.textInputStyle}
placeholder="Enter Name"
returnKeyLabel = {"next"}
onChangeText={(text) => this.setState({username:text})}
/>
<Button style={styles.buttonStyle}>
Submit
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
buttonStyle: {
alignSelf: 'center',
textAlign: 'center',
color: '#FFFFFF',
fontSize:18,
marginTop:20,
marginBottom:20,
padding:5,
borderRadius:5,
borderWidth:2,
width:100,
alignItems: 'center',
backgroundColor:'#4285F4',
borderColor:'#000000'
}
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
You need to pass the props to another page using navigator
this.props.navigator.push({
name: 'Home',
passProps: {
name: property
}
})
i took this from this link https://medium.com/#dabit3/react-native-navigator-navigating-like-a-pro-in-react-native-3cb1b6dc1e30#.6yrqn523n
Initially
import {Navigator}
Define Navigator inside the
render
function of
index.android.js
like this
render() {
return (
<Navigator
initialRoute={{id: 'HomePage', name: 'Index'}}
renderScene={this.renderScene.bind(this)}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}} />
);
}
Then define the
renderscene function
like this
renderScene(route, navigator) {
var routeId = route.id;
if (routeId === 'HomePage') {
return (
<HomePage
navigator={navigator} />
);
}
if (routeId === 'DetailPage') {
return (
<DetailPage
navigator={navigator}
{...route.passProps}
/>
);
}
}
Specify the property
{...route.passProps}
for passing values to a screen. Here I have given it inside the DetailPage
Then you can use
passProps
for calling the next page. In my case
DetailPage
this.props.navigator.push({
id: 'DetailPage',
name: 'DetailPage',
passProps: {
name:value
}
});