importing a screen from the same JS file - react-native

I have consulted every question in StackOverflow regarding this problem with no success. I continuously get the following error `Route 'Home' should declare a screen.
This error seems to indicate that I must import a component into my working file if I want to use it as a screen, is that the case? If so, Why? That's probably what's wrong with my code, otherwise, I'm not sure what is wrong here: I would like to understand why this isn't working, I have consulted multiple guides on the subject.
my index.android.js:
import './app/index.js'
my index.js (not in full):
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, Button, Image, TextInput }
from 'react-native';
import { StackNavigator } from 'react-navigation';
const RallyMobileNavigator = StackNavigator({
Home: { screen: RallyMobile },
LogIn: { screen: LogIn }
},{
initialRouteName: 'Home'
});
class RallyMobile extends Component {
static navigationOptions = {
title: 'Welcome',
};
state = {
initialPosition: {},
lastPosition: {},
userData: [],
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Button
onPress={() => navigate('LogIn')}
title='Sign In'
/>
</View>
<View style={styles.EventListContainer}>
<EventList
location={this.state.lastPosition.location ?
this.state.lastPosition.location :
this.state.initialPosition.location}
/>
</View>
</View>
);
};
};
class LogIn extends Component {
state = {
userName: '',
password: ''
}
static navigationOptions = {
title: 'Sign In',
};
logInUser = () => {
console.log("test");
}
render() {
return(
<View>
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Username"
onChangeText={(text) => this.setState({userName})}
/>
<TextInput
style={{height: 40}}
placeholder="Password"
onChangeText={(text) => this.setState({password})}
/>
</View>
<View>
<button
onPress={logInUser()}
title='Sign In'
/>
</View>
</View>
)
}
}
AppRegistry.registerComponent('RallyMobile', () => RallyMobileNavigator);

Move
const RallyMobileNavigator = StackNavigator({
Home: { screen: RallyMobile },
LogIn: { screen: LogIn }
},{
initialRouteName: 'Home'
});
To just above
AppRegistry.registerComponent('RallyMobile', () => RallyMobileNavigator);
Credit:
https://github.com/react-community/react-navigation/issues/571#issuecomment-284207331

Related

React Native Redux - Not showing updated state via different route

I'm writing a react-native app via expo and trying to implement redux. I'm not sure if I'm going about this completely the wrong way. I have a home page that has two sections, a search text box and an area with links to content pages. The content pages also contain the same search box component. I want to be able to pass the contents of the search box input to the content page so that the user doesn't need to enter this again (and will probably require access to this content further in the user journey)
My app.js looks like the below:
import React from 'react';
import 'react-native-gesture-handler';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import ContentPage from './pages/ContentPage.js';
import LogoTitle from './components/LogoTitle';
import EventsListPage from './pages/EventsListPage.js';
import EventPage from './pages/EventPage';
import VenuePage from './pages/VenuePage';
import HomeScreen from './pages/HomePage';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const initialState ={
postcode:"abcefg"
}
const reducer = (state = initialState, action) => {
switch(action.type)
{
case 'SET_POSTCODE':
return {
postcode: action.text
}
default:
console.log("returning default state")
return state
}
}
const store = createStore(reducer);
const RootStack = createStackNavigator(
{
Home: HomeScreen,
ContentPage: ContentPage,
EventsListPage: EventsListPage,
EventPage: EventPage,
VenuePage: VenuePage
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerTitle: () => <LogoTitle />,
headerLeft: () => null,
headerStyle: {
backgroundColor: '#ADD8E6'
}
},
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>);
}
}
Homepage.js:
import React from 'react';
import { StyleSheet, View } from 'react-native';
import SearchBox from '../components/SearchBox'
import TypeDrillDownArea from '../components/TypeDrillDownArea'
import 'react-native-gesture-handler';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
state = {
};
}
render() {
return (
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId=''/>
<TypeDrillDownArea navigation={this.props.navigation} />
</View>
);
}
}
export default HomeScreen
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch'
},
});
Relevant searchbox.js:
render() {
return (
<ImageBackground source={topperBackground} style={{width: '100%'}}>
<View>
<View style={styles.row}>
<View>
<TextInput
value={this.props.postcode}
autoCapitalize="characters"
style={styles.inputBox}
placeholder="Enter Postcode"
onChangeText={(e) => this.props.setPostcode(e)}
/>
</View>
<View>
<TouchableOpacity
disabled={this.state.locationDisabled}
onPress={() => {
this.props.navigation.navigate('EventsListPage', {
navigation: this.props.navigation,
eventTypeId: this.state.eventTypeId,
locLongitude: this.state.location.coords.longitude,
locLatitude: this.state.location.coords.latitude,
});
}}>
<Image
style={styles.locationPin}
source={locationPin}
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.searchButtonArea}>
<TouchableOpacity
onPress={() => {
console.log("postcode is: " + this.state.postcode)
this.props.navigation.navigate('EventsListPage', {
eventTypeId: this.state.eventTypeId,
postcode: this.props.postcode,
});
}}>
<Text style={styles.searchButton}>SEARCH</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SearchBox)
function mapStateToProps(state){
return {
postcode:state.postcode
}
}
function mapDispatchToProps(dispatch){
return{
setPostcode : (e) => dispatch({
type: 'SET_POSTCODE',
postcode : e
})
}
}
and finally relevant contentpage.js:
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId={this.state.eventTypeId} />
<Image source={imageType(this.state.dataSource[0].eventTypeId)} style={styles.eventType} />
<Text style={styles.textToDisplay}>
{this.state.dataSource[0].eventTypeDescription}
</Text>
</View>
On load, the box is prepopulated with "abcefg" as expected. Changing the contents hits the reducer as expected. However when I navigate to a content page which loads the search box again the value is empty, regardless if I've changed the original state or not.
Am I missusing redux for what it's intended? Should I be doing this a different way?
For clarity below is the organisation of the components
In the reducer(), you are accessing action.text but in the dispatch(), you passed postcode value to postcode instead of text.

I get "Cannot call a class as a function" error when I use a class component as a custom header for another component using react-navigation-stack

This is my class component which I want to use a custom header for my food component.
import React from 'react';
import {Text, View, Image, TouchableOpacity} from 'react-native';
import {styles} from './Food.Styled';
class FoodHeader extends React.Component {
render() {
return (
<View style={styles.container}>
<View style={styles.topContainer}>
<Image
style={styles.icon}
source={require('../../../../images/images.jpeg')}
/>
<Text style={styles.foodTxt}>FOOD</Text>
</View>
<View style={styles.botContainer}>
<View style={styles.leftBotCont1}>
<View style={styles.txtCont1}>
<Text style={styles.txt1}>Monday</Text>
<TouchableOpacity style={styles.txt2Con}>
<Text style={styles.txt2}> (Click to change)</Text>
</TouchableOpacity>
{/* <DateTimePicker
isVisible={isDateTimePickerVisible}
onConfirm={handleDatePicked}
onCancel={hideDateTimePicker}
/> */}
</View>
<View style={styles.txtCont2}>
<Text style={styles.txt3}>October 28</Text>
<Image
style={styles.icon1}
source={require('../../../../images/images.jpeg')}
/>
</View>
</View>
<View style={styles.rightBotCont}>
<Image
style={styles.icon2}
source={require('../../../../images/images.jpeg')}
/>
</View>
</View>
</View>
);
}
}
export default FoodHeader;
I am importing it and using it in a stackNavigator as a custom header for my another component.
import {Food} from './src/modules/food';
import {FoodHeader} from './src/modules/food/foodheader';
const MainStack = createStackNavigator(
{
Profile: {
screen: Profile,
navigationOptions: {
header: null,
},
},
Food: {
screen: Food,
navigationOptions: {
header: FoodHeader,
},
},
},
{
initialRouteName: 'Dashboard',
},
);
But it gives "Cannot call a class as a function" error. When I do not use it as custom header I do not see the error anymore but of course I do not see the header either in my food component.
What am I doing wrong here? Thanks in advance.
Try putting this inside header :<FoodHeader />
const MainStack = createStackNavigator(
{
Profile: {
screen: Profile,
navigationOptions: {
header: null,
},
},
Food: {
screen: Food,
navigationOptions: {
header: <FoodHeader />
},
},
},
{
initialRouteName: 'Dashboard',
},
);

Navigate to a new screen by calling a function onPress

I would like to use my onLogin() function to navigate to the Dashboard view of the Android MVP I'm building. I've been thrown into a React Native project despite not knowing it and I've only just begun my career, so the answer is probably painfully obvious, but after lots of research I can't quite work it out! Hopefully one of you can guide me to the solution.
I've copied the Login view below.
import React, { Component } from 'react';
import {
TouchableHighlight,
TextInput,
Text,
View,
Image
} from 'react-native';
import styles from "./../style/CustomStylesheet";
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
Email: '',
password: '',
};
}
onLogin() {
const { Email, password } = this.state;
//insert function to navigate to dashboard here?
}
render() {
return (
<View style={styles.container}>
<Image
style={styles.logo}
source={require('./../../android/app/src/main/res/drawable/login.png')}
/>
<TextInput
value={this.state.Email}
onChangeText={(Email) => this.setState({ Email })}
placeholder={'Email'}
placeholderTextColor={'#333333'}
style={styles.input}
inlineImageLeft='login_id'
/>
<TextInput
value={this.state.password}
onChangeText={(password) => this.setState({ password })}
placeholder={'Password'}
placeholderTextColor={'#333333'}
secureTextEntry={true}
style={styles.input}
inlineImageLeft='login_password'
/>
<View style={styles.help}>
<Text>Need help?</Text>
</View>
<TouchableHighlight
style={[styles.input, styles.button]}
onPress={this.onLogin.bind(this)}>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableHighlight>
<View style={styles.modal}>
<Text style={styles.modalText}>New user?</Text>
<Text style={styles.modalText}>Register on our web app or our iPad app</Text>
</View>
</View>
);
}
}
I've added the dashboard to my Stack Navigation file too. Any guidance you could give would be wonderful. Many thanks!
import Login from "./Login";
import Dashboard from "./Dashboard";
const AppNavigator = createStackNavigator(
{
Home: { screen: Login },
Dashboard: { screen: Dashboard }
},
{
headerMode: 'none'
}
);
export default createAppContainer(AppNavigator);
add this
onLogin=()=> {
const { Email, password } = this.state;
const { navigation } = this.props;
navigation.navigate('Dashboard');
}

The component of route "WelcomeScreen" must be react component

I am having a problem with this little piece of code. I have almost searched about this error everywhere but it did not solved my problem. I have used all the methods given by experts regarding tenter image description herehat problem. Please If anyone can help.
///app.js
import {
createStackNavigator,
createAppContainer
} from 'react-navigation';
import React, {Component} from 'react';
import {AppRegistry} from 'react-native';
import WelcomeScreen from './Components/Welcome/Welcome';
import SignInScreen from './Components/SingIn/SingIn';
import SignUpScreen from './Components/SingUp/SingUp';
import ContinueAsGuestScreen from './Components/ContinueAsGuest/ContinueAsGuest';
const RootStack = createStackNavigator({
WelcomeScreen: {
WelcomeScreen: WelcomeScreen
},
SignInScreen: {
SignInScreen: SignInScreen
},
SignUpScreen: {
SignUpScreen: SignUpScreen
},
ContinueAsGuestScreen: {
ContinueAsGuestScreen: ContinueAsGuestScreen
},
});
const App = createAppContainer(RootStack);
export default App;
**I have used all the techniques specially exporting things I found but of no help*
Here is Welcom.js
import React, { Component } from 'react';
import { Platform, AppRegistry, StyleSheet, Text, View, TextInput, TouchableOpacity } from 'react-native';
import symbolicateStackTrace from 'react-native/Libraries/Core/Devtools/symbolicateStackTrace';
import { ScrollView } from 'react-native-gesture-handler';
export default class Welcome extends Component {
static navigatonOptions =
{ title: 'Welcome Screen' };
constructor(props) {
super(props);
this.handleButton = this.handleButton.bind(this);
state =
{
Firstname: '',
Lastname: '',
EmailAddress: '',
PhoneNumber: '',
CompanyName: '',
OtherEmailAddress: ''
}
}
handleFirstName = (text) => {
this.setState({ FirstName: text })
}
handleLastName = (text) => {
this.setState({ Lastname: text })
}
handleEmailAddress = (text) => {
this.setState({ EmailAddress: text })
}
handlePhoneNumber = (text) => {
this.setState({ PhoneNumber: text })
}
handleCompanyName = (text) => {
this.setState({ CompanyName: text })
}
handleOtherEmailAddress = (text) => {
this.setState({ OtherEmailAddress: text })
}
handleButton = () => {
this.props.navigation.navigate("SignInScreen");
}
render() {
return (
<ScrollView style={styles.container} >
<View style={styles.header}>
<Text style={{ fontSize: 20 }}> Profile </Text>
</View>
<View>
<Text style={{ fontSize: 20, alignSelf: "center" }}> Welcome here </Text>
</View>
<Text>FIRST NAME *</Text>
<TextInput style={styles.input}
placeholder="Firstname"
placeholderTextColor="#9a73ef"
AutoCapitalization="none"
onChangeText={this.handleFirstName}
/>
<Text>LAST NAME *</Text>
<TextInput style={styles.input}
placeholder="LastName"
placeholderTextColor="#9a73ef"
AutoCapitalization="none"
onChangeText={this.handleLastName}
/>
<Text>Email Address *</Text>
<TextInput style={styles.input}
placeholder="Email Address"
placeholderTextColor="#9a73ef"
AutoCapitalization="none"
onChangeText={this.handleEmailAddress}
/>
<Text>PHONE NUMBER *</Text>
<TextInput style={styles.input}
placeholder="Phone Number"
placeholderTextColor="#9a73ef"
AutoCapitalization="none"
onChangeText={this.handlePhoneNumber}
/>
<Text>COMPANY NAME *</Text>
<TextInput style={styles.input}
placeholder="Company Name"
placeholderTextColor="#9a73ef"
AutoCapitalization="none"
onChangeText={this.handleCompanyName}
/>
<Text>OTHER EMAIL ADDRESS *</Text>
<TextInput style={styles.input}
placeholder="Other Email Address"
placeholderTextColor="#9a73ef"
AutoCapitalization="none"
onChangeText={this.handleOtherEmailAddress}
/>
<TouchableOpacity style={styles.submitButton2} onPress={() => this.handleButton} >
<Text style={styles.submitButtonText}> Save </Text>
</TouchableOpacity>
</ScrollView>
);
}
}
I think you're creating the navigator uncorrectly in createStackNavigator(). Try this:
const RootStack = createStackNavigator({
WelcomeScreen: {
screen: WelcomeScreen
},
SignInScreen: {
screen: SignInScreen
},
SignUpScreen: {
screen: SignUpScreen
},
ContinueAsGuestScreen: {
screen: ContinueAsGuestScreen
},
});

Can't navigate to other screen from the screen in TabNavigator

I trying to render StackNavigator inside TabNavigator. The Tabs are working fine, but i cannot link the button
In simple words, there's a button inside the "Feed" section of the TabNavigator "Tabs" . When clicked on the button, it should go to "UserDetails.js" via StackNavigator.
Please help!
Here is my index.android.js
export default class HackernoonNavigation extends Component {
render() {
return (
<Tabs />
);
}
}
export const Tabs = TabNavigator({
Feed: {
screen: Feed,
},
Me: {
screen: Me,
},
});
And here is the file "Feed.js" , inside which there is a button that leads to "UserDetail.js"
export default class Feed extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to Feed!
</Text>
<Button
onPress={() => this.props.navigation.navigate('Details')}
title="User Details"
/>
</View>
);
}
}
export const FeedStack = StackNavigator({
Details: { screen: UserDetail },
});
You can do it by defining tabnavigator inside stacknavigator as screen like in this way -
const StackNaviApp = StackNavigator({
UserDetails: { screen: UserDetails},
Feed: {
screen: TabNavigator({
Feed: { screen: Feed},
Me: { screen: Me}
}, {
tabBarOptions: {
showIcon: true,
lazy: true,
activeTintColor: '#7567B1',
labelStyle: {
fontSize: 16,
fontWeight: '600'
}
}
})
}});
export default StackNaviApp;
Taking Feed & Me inside TabNavigator & UserDetails inside StackNavigator directly . For more detail you can refer the source code from here -
http://androidseekho.com/others/reactnative/switching-between-stack-navigator-to-tab-navigator/
So I have a ListView on a Tab Screen and when I click on the List Item its navigating to a component called QR Code. So when I click a List Item the camera will be opened in a new window with StackNavigator.... I show you my code down below. Maybe it helps you to find your fault.
import React, {
Component,
} from 'react';
import {
// AppRegistry,
// Dimensions,
ListView,
StyleSheet,
Text,
TouchableOpacity,
TouchableHighlight,
View,
AsyncStorage
} from 'react-native';
import { SwipeListView, SwipeRow } from 'react-native-swipe-list-view';
import moment from 'moment';
import{createStackNavigator} from 'react-navigation';
import { Icon } from 'react-native-elements'
import QrCode from '../components/QrCode';
class SwipeList extends Component {
static navigationOptions = {
title: 'Scanner auswählen',
headerTintColor: 'white',
headerStyle: {backgroundColor: '#444444'},
headerTitleStyle: { color: 'white' },
};
constructor(props) {
super(props);
this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
scannerAvailable:false,
listType: 'FlatList',
listViewData: this.ds,
}
...
goToQrCodeScreen=(scanner)=>{
this.props.navigation.navigate('QrCode',{
scannerName: scanner.scannerName,
scannerValidityEnd: scanner.scannerValidityEnd,
scannerId: scanner.scannerId,
dataMacroId: scanner.dataMacroId,
hash:scanner.hash,
requestKey: scanner.requestKey,
})
}
...
render() {
return (
<View style={styles.container}>
<View>
<SwipeListView
dataSource={this.state.listViewData}
renderRow={ data => (
<View >
<TouchableHighlight
onPress={()=>this.goToQrCodeScreen(data)}
style={styles.rowFront}
underlayColor={'#AAA'}>
<Text> <Text style={[styles.listItemName,styles.textBold] } >{data.scannerName} </Text>
<Text style={styles.listItemValid}> gültig bis {moment(data.scannerValidityEnd).format('DD.MM.YYYY')}</Text>
</Text>
</TouchableHighlight>
</View>
)}
renderHiddenRow={ (data, secId, rowId, rowMap) => (
<View style={styles.rowBack}>
<TouchableOpacity style={[styles.backRightBtn, styles.backRightBtnRight]} onPress={ _ => this.deleteRow(data.scannerId,rowMap, `${secId}${rowId}`) }>
<Icon
name='trash'
type='font-awesome'
color='white'/>
<Text style={styles.backTextWhite}>
Löschen</Text>
</TouchableOpacity>
</View>
)}
rightOpenValue={-100}
enableEmptySections={true}
/>
</View>
</View>
);
}
}
const StackNavigation = createStackNavigator(
{
SwipeList:SwipeList ,
QrCode:QrCode
},
{
initialRouteName: 'SwipeList',
}
);
export default StackNavigation;
I deleted the code you dont need. I call the method goToQrCodeScreen() to navigate.
My fault was that I dont exported the StackNavigator. Now its working.
you need to wrap your feed in another component :
const FeedStack = createStackNavigator();
function FeedWrapper() {
return (
<HomeStack.Navigator>
<FeedStack .Screen name="Feed" component={Feed} />
<FeedStack .Screen name="Details" component={Details} />
</HomeStack.Navigator>
);
}
see https://reactnavigation.org/docs/tab-based-navigation