React-native Undefined is not an object(this.props.navigation.navigate) - react-native

I'm attempting to navigate from the login page to the welcome page upon successful login using firebase using a method called submit (located within loginForm). Everything is working with the exception of the navigation, using StackNavigation, to the Welcome page.
I've looked through every post on this error and tried countless fixes using solutions posted all over but can't seem to come up with any fix. I'm sure its a simple and goofy error I'm making here. I would greatly appreciate any help.
(Apologies in advance, this is my first react-native project)
Thank you!
App.js
import React from 'react';
import * as firebase from 'firebase';
import {StackNavigator} from "react-navigation";
import Login from './src/components/Login/Login';
import Welcome from "./src/components/Welcome";
export const AppNavigator = StackNavigator({
Login: {screen: Login},
Welcome: {screen: Welcome},
});
//initialize Firebase
const firebaseConfig = {
apiKey: "************************************",
authDomain: "firstproject-r.firebaseapp.com",
databaseURL: "https://firstproject-r.firebaseio.com",
projectId: "firstproject-r",
storageBucket: "",
messagingSenderId: "************"
};
firebase.initializeApp(firebaseConfig);
class App extends React.Component {
render() {
return (
<AppNavigator/>
);
}
}
export default App;
login.js
import React from 'react';
import {StyleSheet, View, Image, Text, KeyboardAvoidingView, StatusBar}
from 'react-native';
import LoginForm from "./LoginForm";
class Login extends React.Component {
render() {
const { navigate } = this.props.navigation;
return (
<KeyboardAvoidingView behavior='padding' style=
{styles.container}>
<View style={styles.logoContainer}>
<StatusBar barStyle="light-content"/>
<Image
style={styles.logo}
source=
{require('../../images/EquipRentIcon.png')}>
</Image>
<Text style={styles.title}>idostuff</Text>
</View>
<View style={styles.formContainer}/>
<LoginForm/>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#3498db',
},
logo: {
width: 160,
height: 160
},
logoContainer: {
alignItems: 'center',
flexGrow: 1,
justifyContent: 'center'
},
title: {
color: '#FFF',
fontSize: 20,
justifyContent: 'center'
},
formContainer: {}
});
export default Login;
loginForm.js
import React from 'react';
import {StyleSheet, Text, View, TextInput, TouchableOpacity, StatusBar} from 'react-native';
import firebase from 'firebase';
// const auth = firebase.auth();
// const fbProvidor = new firebase.auth.FacebookAuthProvider();
// const googProvidor = new firebase.auth.GoogleAuthProvider();
class LoginForm extends React.Component {
constructor(props) {
super(props)
this.submit = this.submit.bind(this);
this.loginUser = this.loginUser.bind(this);
this.createUser = this.createUser.bind(this);
this.state = ({
email: '',
password: '',
navigation: this.props.navigation
})
}
loginUser = (email, password, ) => {
try {
if (this.state.password.length < 6) {
alert("Please enter at least 6 characters")
return;
}
firebase.auth().signInWithEmailAndPassword(email, password).then(function (user) {
console.log(user)
});
this.submit()
}
catch (error) {
console.log(error.toString())
}
};
createUser = (email, password) => {
try {
if (this.state.password.length < 6) {
alert("Please enter at least 6 characters")
return;
}
firebase.auth().createUserWithEmailAndPassword(email, password).then(function () {
});
this.submit()
}
catch (error) {
console.log(error.toString())
}
};
submit() {
this.props.navigation.navigate('Welcome');
}
render() {
return (
<View style={styles.container}>
<StatusBar barStyle="light-content"/>
<TextInput
style={styles.input}
returnKeyType="next"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
placeholder="username"
onSubmitEditing={() => this.passwordInput.focus()}
onChangeText={(email) => this.setState({email})}
placeholderTextColor="rgba(255, 255, 255, 0.7)">
</TextInput>
<TextInput
style={styles.input}
placeholder="password"
secureTextEntry
returnKeyType="go"
ref={(input) => this.passwordInput = input}
onChangeText={(password) => this.setState({password})}
placeholderTextColor="rgba(255, 255, 255, 0.7)">
</TextInput>
<TouchableOpacity
style={styles.loginButtonContainer}
onPress={() => {
this.loginUser(this.state.email, this.state.password)
}}
>
<Text style={styles.loginButtonText}>
Login
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.signupButtonContainer}
onPress={() => {
this.createUser(this.state.email, this.state.password)
}}
>
<Text style={styles.signUpButtonText}>
Sign Up
</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
padding: 20
},
input: {
height: 40,
backgroundColor: 'rgba(255, 255, 255, 0.3)',
marginBottom: 15,
fontSize: 20,
paddingHorizontal: 10
},
loginButtonContainer: {
backgroundColor: '#2980b9',
padding: 15,
justifyContent: 'center'
},
signupButtonContainer: {
backgroundColor: 'white',
opacity: .3,
marginTop: 10,
padding: 15,
justifyContent: 'center'
},
loginButtonText: {
textAlign: 'center',
color: 'white',
fontSize: 20,
fontWeight: '700'
},
signUpButtonText: {
textAlign: 'center',
color: 'black',
fontSize: 20,
fontWeight: '700'
}
});
export default LoginForm;
welcome.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
class Welcome extends React.Component{
render() {
const { navigate } = this.props.navigation;
return (
<Text>
this is the welcome screen
</Text>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#3498db',
},
});
export default Welcome;

Related

How to navigate dashboard when login successful in React native?

I have implemented some code in react native, to connect with the express backend. This only works for all the users without the role == admin. I could able to print the Successfully logged! in console. But now I need to navigate to the dashboard. How can I do that. I don't know how to do that. another thing is in the touchableOpacity I saw the attribute called value. But I can't find the meaning of that. Please help me in this regard. Also I have attach the service file also.
import React, {useState} from 'react';
import {
View,
Text,
TouchableOpacity,
TextInput,
StyleSheet,
StatusBar,
Dimensions,
} from 'react-native';
import {useTheme} from '#react-navigation/native';
import * as Animatable from 'react-native-animatable';
import LinearGradient from 'react-native-linear-gradient';
import axios from 'axios';
import {hostName} from '../../constants/constants';
import {login} from '../../services/authService';
import AsyncStorage from '#react-native-community/async-storage';
const SigninPage = ({navigation}) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const {colors} = useTheme();
const signIn = () => {
login(email, password)
.then((res) => {
// if (res.data.role == 'admin') {
// throw new Error('Cannot login');
// } else {
AsyncStorage.setItem('userData', JSON.stringify(res.data.dbResult[0]));
AsyncStorage.setItem('userRole', res.data.role);
AsyncStorage.setItem('userToken', res.data.token);
console.log('successfully logged!');
// }
})
.catch((err) => {
console.log(err);
});
};
return (
<View style={{flex: 1, backgroundColor: '#000e60'}}>
<StatusBar backgroundColor="#009387" barStyle="light-content" />
<View style={styles.header}>
<Animatable.Image
animation="bounceIn"
duraton="1500"
source={require('../../assets/img/afisolve_logo.png')}
style={styles.logo}
resizeMode="stretch"
/>
</View>
<Animatable.View
style={[
styles.footer,
{
backgroundColor: colors.background,
},
]}
animation="fadeInUpBig">
<Text style={styles.signinTop}>Sign in with your account</Text>
<View style={styles.inputView}>
<TextInput
style={styles.TextInput}
placeholder="Email"
placeholderTextColor="white"
onChangeText={(email) => setEmail(email)}
/>
</View>
<View style={styles.inputView}>
<TextInput
style={styles.TextInput}
placeholder="Password"
placeholderTextColor="white"
secureTextEntry={true}
onChangeText={(password) => setPassword(password)}
/>
</View>
<TouchableOpacity onPress={() => signIn()}>
<LinearGradient colors={['#730018', '#00085b']} style={styles.signIn}>
<Text style={styles.textSign}>SIGN IN</Text>
</LinearGradient>
</TouchableOpacity>
<Text>Fogot Your Password?</Text>
</Animatable.View>
</View>
);
};
export default SigninPage;
const {height} = Dimensions.get('screen');
const height_logo = height * 0.28;
const styles = StyleSheet.create({
header: {
flex: 2,
justifyContent: 'center',
alignItems: 'center',
},
logo: {
width: height_logo,
height: height_logo,
borderRadius: 150 / 3,
},
footer: {
flex: 1,
backgroundColor: '#fff',
borderTopLeftRadius: 30,
borderTopRightRadius: 30,
paddingVertical: 50,
paddingHorizontal: 30,
alignItems: 'center',
justifyContent: 'center',
},
inputView: {
backgroundColor: '#2937f6',
width: '70%',
height: 45,
marginBottom: 20,
alignItems: 'center',
},
textSign: {
color: 'white',
fontWeight: 'bold',
},
signIn: {
width: 150,
height: 40,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 50,
flexDirection: 'row',
},
signinTop: {
color: '#000000',
fontSize: 20,
fontWeight: 'bold',
paddingBottom: 25,
},
});
Service file
import axios from 'axios';
import {hostName} from '../constants/constants';
export const login = (email, password) => {
return axios.post(hostName + '/authentication/login', {
email: email,
password: password,
});
};
this may help you
const signIn = () => {
login(email, password)
.then((res) => {
// if (res.data.role == 'admin') {
// throw new Error('Cannot login');
// } else {
AsyncStorage.setItem('userData', JSON.stringify(res.data.dbResult[0]));
AsyncStorage.setItem('userRole', res.data.role);
AsyncStorage.setItem('userToken', res.data.token);
console.log('successfully logged!');
//here
navigation.replace('Home');//if you don't wanna call login back
//else
navigation.navigate('Home');
// }
})
.catch((err) => {
console.log(err);
});
};
I use this tutorial to implement the Authentication flows.
Basically, you retrieve your access token, then store it in redux/context. Your Navigator detects that the user has an access token and change the screens available.
I have found a good answer to my question. If someone got the same stuck, will help you following the corrected issue.
const signIn = () => {
login(email, password)
.then((res) => {
// if (res.data.role == 'admin') {
// throw new Error('Cannot login');
// } else {
AsyncStorage.setItem('userData', JSON.stringify(res.data.dbResult[0]));
AsyncStorage.setItem('userRole', res.data.role);
AsyncStorage.setItem('userToken', res.data.token);
console.log('successfully logged!');
navigation.navigate('Home');
// }
})
.catch((err) => {
console.log(err);
});
};

I need to show Alert modal in every screen when intenet is down

I need to show NetAlert modal in every screen when intenet is down. I have created a NetAlertModal component for that . I am not sure where to render this component . I am using react navigation Switch navigator. If I am rendering as below it is not showing login screen.
I am new to react native so please help.
Below is my code
/***App.js*/
render() {
return (
<Provider store={store}>
<PersistGate>
<Fragment>
<StatusBar barStyle="dark-content" />
<SafeAreaView
style={styles.safeArea}
forceInset={{bottom: 'never', top: 'never'}}>
<NetAlertModal /> <------ Need to show this
<RootNav
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
</SafeAreaView>
</Fragment>
</PersistGate>
</Provider>
);
}
}
/*rootNav.js*/
const RootNav = createSwitchNavigator(
{
Drawer: DrawerNavigator,
Auth: AuthStack,
},
{
initialRouteName: 'Auth',
},
);
export default createAppContainer(RootNav);
*/AuthStack.js*/
import {createStackNavigator} from 'react-navigation';
import Login from '../components/login/Login';
import Verify from '../components/verify/Verify';
const rootConfiguration = {
loginPage: {screen: Login},
verifyPage: {screen: Verify},
};
const stackNavigatorConfiguration = {
initialRouteName: 'loginPage',
headerMode: 'none',
defaultNavigationOptions: {
headerTintColor: '#ffeb3b',
headerTitleStyle: {
fontWeight: 'bold',
flex: 1,
textAlign: 'center',
},
},
};
export const AuthStack = createStackNavigator(
rootConfiguration,
stackNavigatorConfiguration,
);
Try this below example in your app.js which I create using #react-native-community/netinfo library
import React, { Component } from 'react';
import NetInfo from "#react-native-community/netinfo";
import { View, Text, Modal } from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isConnected: true,
};
}
componentDidMount() {
NetInfo.isConnected.addEventListener('connectionChange', this.handleConnectivityChange);
}
componentWillUnmount() {
NetInfo.isConnected.removeEventListener('connectionChange', this.handleConnectivityChange);
}
handleConnectivityChange = isConnected => {
this.setState({ isConnected });
};
render() {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{/* your app */}
</View>
{
!this.state.isConnected &&
<Modal
visible={!this.state.isConnected}
transparent={true}
animationType='slide'
>
<View style={styles.modelStyle}>
<View style={styles.modelWrapperStyle}>
<Text style={{ textAlign: 'center' }}>{global.strings.oops}</Text>
<Text style={{ textAlign: 'center' }}>{global.strings.internetConnection}</Text>
</View>
</View>
</Modal>
}
</View>
);
}
}
const styles = {
modelStyle: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.5)'
},
modelWrapperStyle: {
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#e3dfde',
padding: 20,
width: '90%',
borderRadius: 20
},
};
export default App;
Change this according to your requirement. Feel free for doubts.
import { NetInfo } from 'react-native';
NetInfo.isConnected.fetch().then(isConnected => {
if(isConnected)
{
console.log('Internet is connected');
}
})
use above code as a HOC or make it global for your root file

Convert React Native functional components to class components

I'm new to React Native and after following some tutorials I hacked this together but now I want to load some gifs right when the app starts - not after the button click.
Did some research and it looks like it's not possible with functional components and I need to switch to class components to use lifecycle functions like:
componentWillMount(){
this.setState({data : inputObject});
}
All the examples I've read so far don't have functions in their components and I can't figure out what to do with them. So if it is possible to call a function when the app starts using this as is please let me know how, if not, how do I convert this code to class component style? Thanks!
import React, {useState} from 'react';
import {
Dimensions,
StyleSheet,
SafeAreaView,
View,
Image,
FlatList,
} from 'react-native';
import SearchInput from './SearchInput';
export default function App() {
const [allGifResults, setAllGifResults] = useState([]);
function addSearchResultsHandler(searchTerm) {
console.log(searchTerm);
setAllGifResults([]);
fetchResults(searchTerm);
}
function allGifResultsHandler(url) {
setAllGifResults(currentGifs => [...currentGifs, {id: url, value: url}]);
}
function fetchResults(searchTerm) {
fetch(
'http://api.giphy.com/v1/gifs/search?q=' +
searchTerm +
'&api_key=MKSpDwx7kTCbRp23VtVsP4d0EvfwIgSg&limit=50',
)
.then(response => response.json())
.then(responseJson => {
for (let item of responseJson.data) {
allGifResultsHandler(item.images.fixed_height.url);
console.log(item.images.fixed_height.url);
}
})
.catch(error => {
console.error(error);
});
}
return (
<SafeAreaView style={styles.container}>
<View style={styles.screen}>
<SearchInput onSearchButtonPressed={addSearchResultsHandler} />
</View>
<FlatList
keyExtractor={(item, index) => item.id}
data={allGifResults}
numColumns={2}
renderItem={itemData => (
<Image
source={itemData.item.value ? {uri: itemData.item.value} : null}
style={styles.images}
/>
)}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
screen: {
margin: 10,
},
images: {
width: Dimensions.get('window').width / 2 - 20,
height: Dimensions.get('window').width / 2 - 20,
margin: 10,
},
});
import React, {useState} from 'react';
import {
View,
TextInput,
TouchableOpacity,
Text,
StyleSheet,
} from 'react-native';
function SearchInput(props) {
const [searchTerm, setSearchTerm] = useState('');
function inputHandler(enteredText) {
setSearchTerm(enteredText);
}
return (
<View style={styles.inputContainer}>
<TextInput
placeholder="Search Term"
style={styles.input}
onChangeText={inputHandler}
value={searchTerm}
/>
<TouchableOpacity
style={styles.searchButton}
onPress={props.onSearchButtonPressed.bind(this, searchTerm)}>
<Text style={styles.searchButtonText}>Search</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
inputContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginBottom: 20,
},
input: {
width: '70%',
borderColor: 'black',
borderWidth: 1,
fontSize: 16,
},
searchButton: {
height: 50,
width: 100,
backgroundColor: 'lightblue',
marginLeft: 10,
},
searchButtonText: {
height: 50,
fontSize: 18,
textAlign: 'center',
textAlignVertical: 'center',
},
});
export default SearchInput;
import React, {useState} from 'react';
import {
Dimensions,
StyleSheet,
SafeAreaView,
View,
Image,
FlatList,
} from 'react-native';
import SearchInput from './SearchInput';
const [allGifResults, setAllGifResults] = useState([]);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.addSearchResultsHandler = this.addSearchResultsHandler.bind(this);
this.allGifResultsHandler = this.allGifResultsHandler.bind(this);
this.fetchResults = this.fetchResults.bind(this);
}
addSearchResultsHandler(searchTerm) {
console.log(searchTerm);
setAllGifResults([]);
fetchResults(searchTerm);
}
allGifResultsHandler(url) {
setAllGifResults(currentGifs => [...currentGifs, {id: url, value: url}]);
}
fetchResults(searchTerm) {
fetch(
'http://api.giphy.com/v1/gifs/search?q=' +
searchTerm +
'&api_key=MKSpDwx7kTCbRp23VtVsP4d0EvfwIgSg&limit=50',
)
.then(response => response.json())
.then(responseJson => {
for (let item of responseJson.data) {
allGifResultsHandler(item.images.fixed_height.url);
console.log(item.images.fixed_height.url);
}
})
.catch(error => {
console.error(error);
});
}
render(){
return (
<SafeAreaView style={styles.container}>
<View style={styles.screen}>
<SearchInput onSearchButtonPressed={(data)=> this.addSearchResultsHandler(data)} />
</View>
<FlatList
keyExtractor={(item, index) => item.id}
data={allGifResults}
numColumns={2}
renderItem={itemData => (
<Image
source={itemData.item.value ? {uri: itemData.item.value} : null}
style={styles.images}
/>
)}
/>
</SafeAreaView>
);
}
}
export default App;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
screen: {
margin: 10,
},
images: {
width: Dimensions.get('window').width / 2 - 20,
height: Dimensions.get('window').width / 2 - 20,
margin: 10,
},
});
import React, {useState} from 'react';
import {
View,
TextInput,
TouchableOpacity,
Text,
StyleSheet,
} from 'react-native';
const [searchTerm, setSearchTerm] = useState('');
class SearchInput extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.inputHandler = this.inputHandler.bind(this);
}
inputHandler(enteredText) {
setSearchTerm(enteredText);
}
render(){
return (
<View style={styles.inputContainer}>
<TextInput
placeholder="Search Term"
style={styles.input}
onChangeText={inputHandler}
value={searchTerm}
/>
<TouchableOpacity
style={styles.searchButton}
onPress={props.onSearchButtonPressed.bind(this, searchTerm)}>
<Text style={styles.searchButtonText}>Search</Text>
</TouchableOpacity>
</View>
);
}
}
export default SearchInput;
const styles = StyleSheet.create({
inputContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginBottom: 20,
},
input: {
width: '70%',
borderColor: 'black',
borderWidth: 1,
fontSize: 16,
},
searchButton: {
height: 50,
width: 100,
backgroundColor: 'lightblue',
marginLeft: 10,
},
searchButtonText: {
height: 50,
fontSize: 18,
textAlign: 'center',
textAlignVertical: 'center',
},
});
export default SearchInput;

How do I add Redux implementation in my code?

I want to add redux implementation to my simple Login application with some react navigations.
This is my App.js file where I'm importing my AppDrawerNavigator
import React, {Component} from 'react';
import {createAppContainer, createStackNavigator} from 'react-navigation';
import HomeScreen from './screens/HomeScreen.js';
/** Importing navigator */
import AppDrawerNavigator from './drawerNavigator';
class App extends React.Component {
render() {
return <AppContainer />;
}
}
export default App;
const AppStackNavigator = createStackNavigator(
{
Home: {screen: HomeScreen},
Welcome: AppDrawerNavigator
},
{
initialRouteName: 'Home',
headerMode: "none",
}
);
const AppContainer = createAppContainer(AppStackNavigator);
This is my index.js file pointing to my main App.js file
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
Below shows my different screen files.
HomeScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TouchableOpacity,
Alert,
Keyboard,
TextInput,
} from 'react-native';
//HomeScreen
export default class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {username: null, password: null, isPasswordHidden: true, toggleText: 'Show'};
}
handleToggle = () => {
const { isPasswordHidden } = this.state;
if (isPasswordHidden) {
this.setState({isPasswordHidden: false});
this.setState({toggleText: 'Hide'});
} else {
this.setState({isPasswordHidden: true});
this.setState({toggleText: 'Show'});
}
}
//Validate() to check whether the input username is in Mail format
validate = (inputValue) => {
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/ ; // Regex for Emails
// let reg = /^(\+\d{1,3}[- ]?)?\d{10}$/; // Regex for phone numbers
return reg.test(inputValue);
}
clearText(fieldName) {
this.refs[fieldName].clear(0);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}></Text>
<TextInput
ref={'input1'}
style={styles.input}
placeholder="Username"
onChangeText={value => this.setState({username: value})}
// placeholderTextColor="Grey"
// maxLength={13} // For Indian phone numbers
// onChangeText={(text) => this.validate(text)}
// value={this.state.username}
/>
<TextInput
ref={'input2'}
style={styles.input}
placeholder="Password"
maxLength={10}
secureTextEntry={this.state.isPasswordHidden}
onChangeText={value => this.setState({password: value})}
// placeholderTextColor="rgb(225,225,225)"
/>
<TouchableOpacity
onPress={this.handleToggle}
>
<Text>{this.state.toggleText}</Text>
</TouchableOpacity>
<View style={{padding: 20}}>
<TouchableOpacity onPress={() => {
if (!this.validate(this.state.username)) {
Alert.alert("Invalid");
Keyboard.dismiss();
} else if (this.state.username === 'vinay#gmail.com' && this.state.password === 'password') {
//Alert.alert("Login Successful");
if(this.state.username && this.state.password){
this.props.navigation.navigate('Welcome', {
username: this.state.username,
password: this.state.password,
});
this.setState({username: ""});
this.setState({password: ""});
}else{
alert("Invalid");
}
Keyboard.dismiss();
this.clearText('input1');
this.clearText('input2');
} else if (this.state.username === null && this.state.password === null) {
Alert.alert("Invalid");
} else {
Alert.alert("Login Failed");
this.clearText('input1');
this.clearText('input2');
Keyboard.dismiss();
}
}}>
<View style={styles.button}>
<Text style={styles.buttonText}>LOGIN</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
}
});
This is the screen ProfileScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
Image,
View,
} from 'react-native';
export default class Profile extends Component {
render() {
return(
<View>
<Image
style={styles.image}
source={{uri: 'https://facebook.github.io/react/logo-og.png'}}
/>
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
},
image: {
width: 200,
height: 200,
margin: 10
}
});
This is the screen SettingsScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
} from 'react-native';
export default class Settings extends Component {
render() {
return(
<View style={styles.container}>
<Text>Settings</Text>
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
}
});
This is the screen TabA.js
import React, { Component } from 'react'
import {
View,
Text,
StyleSheet,
} from 'react-native'
export default class TabA extends React.Component {
// static navigationOptions = ({ navigation }) => ({
// title: 'Tab A',
// })
render () {
return (
<View style={styles.container}>
<Text style={styles.text}>I'm Tab A</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#c0392b',
padding: 20,
},
text: {
color: 'white',
fontSize: 40,
fontWeight: 'bold',
}
})
This is the screen TabB.js
import React, { Component } from 'react'
import {
View,
Text,
StyleSheet,
} from 'react-native'
export default class TabB extends React.Component {
// static navigationOptions = ({ navigation }) => ({
// title: 'Tab B',
// })
render () {
return (
<View style={styles.container}>
<Text style={styles.text}>I'm Tab B</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#8e44ad',
padding: 20,
},
text: {
color: 'white',
fontSize: 40,
fontWeight: 'bold',
}
})
This is the screen WelcomeScreen.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
} from 'react-native';
export default class WelcomeScreen extends Component {
render() {
const { navigation } = this.props;
const u_name = navigation.getParam('username', 'name');
const p_word = navigation.getParam('password', 'word');
return (
<View style={styles.container}>
<Text style={styles.welcome}>WELCOME</Text>
<Text>USERNAME: {JSON.stringify(u_name)}</Text>
<Text>PASSWORD: {JSON.stringify(p_word)}</Text>
{/* <View style={{padding: 20}}>
<Button style={{margin: 20}}
title="LOGOUT"
onPress={() => this.props.navigation.navigate('Home')}
/>
</View> */}
</View>
);
}
}
/** Stylesheets Defined **/
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
margin: 10,
padding: 20
// textAlign: 'center',
},
input:{
// height: 40,
// margin: 10,
width: 260,
backgroundColor: 'lightgrey',
marginBottom: 10,
padding: 10,
color: 'black'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3',
fontWeight: 'bold'
},
buttonText: {
padding: 20,
color: 'white'
}
});
Below shows my different navigator files
This is the drawer navigator file drawerNavigator.js
import React, {Component} from 'react';
import {
View,
Button,
SafeAreaView,
} from 'react-native';
import {
createDrawerNavigator,
DrawerItems,
} from 'react-navigation';
import TabA from './screens/TabA.js';
import TabB from './screens/TabB.js';
import WelcomeStackNavigator from './stackNavigator';
class Hidden extends React.Component {
render() {
return null;
}
}
const AppDrawerNavigator = createDrawerNavigator({
Welcome: {
screen: WelcomeStackNavigator,
navigationOptions: {
drawerLabel: <Hidden />
}
},
TabA: { screen: TabA },
TabB: { screen: TabB },
// TabC: { screen: TabC },
},{
contentComponent:(props) => (
<View style={{flex:1}}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {...props} />
<Button
title="Logout"
onPress={() => {
props.navigation.navigate('Home')
}}
/>
</SafeAreaView>
</View>
),
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle'
})
export default AppDrawerNavigator;
This is the stack navigator file stackNavigator.js
import React, {Component} from 'react';
import Icon from 'react-native-vector-icons/Ionicons';
import {
createStackNavigator,
} from 'react-navigation';
import WelcomeTabNavigator from './tabNavigator';
const WelcomeStackNavigator = createStackNavigator({
WelcomeTabNavigator: WelcomeTabNavigator
},
{
defaultNavigationOptions:({navigation}) => {
return {
headerLeft: (
<Icon
style={{paddingLeft: 20}}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
}
);
export default WelcomeStackNavigator;
This is the tab navigator file tabNavigator.js
import React, {Component} from 'react';
import WelcomeScreen from './screens/WelcomeScreen.js';
import Profile from './screens/ProfileScreen.js';
import Settings from './screens/SettingsScreen.js';
import Icon from 'react-native-vector-icons/Ionicons';
import {
createBottomTabNavigator,
} from 'react-navigation';
const WelcomeTabNavigator = createBottomTabNavigator(
{
Welcome: {
screen: WelcomeScreen,
navigationOptions: {
tabBarIcon: ({tintColor}) => (
<Icon
name="md-home"
size={20}
/>
)
}
},
Profile: {
screen: Profile,
navigationOptions: {
tabBarIcon: ({tintColor}) => (
<Icon
name="md-book"
size={20}
/>
)
}
},
Settings: {
screen: Settings,
navigationOptions: {
tabBarIcon: ({tintColor}) => (
<Icon
name="md-settings"
size={20}
/>
)
}
},
},
{
tabBarOptions: {
activeTintColor: '#fb9800',
inactiveTintColor: '#7e7b7b',
style: { height: 40,backgroundColor: '#fff',borderTopWidth:0.5,borderTopColor: '#7e7b7b' },
labelStyle: {fontSize: 15}
},
// navigationOptions:({navigation}) => {
// const {routeName} = navigation.state.routes[navigation.state.index];
// return {
// headerTitle: routeName
// };
// },
navigationOptions:({navigation}) => {
const {routeName} = navigation.state.routes[navigation.state.index];
return {
headerTitle: routeName,
// headerLeft: (
// <Icon
// style={{paddingLeft: 20}}
// onPress={() => navigation.openDrawer()}
// name="md-menu"
// size={30}
// />
// )
};
}
}
)
export default WelcomeTabNavigator;
How do I structure my project and add redux implementation on this login application?
Have you checked their doc? https://redux.js.org/
also, you can see ignite boilerplate implementation for redux in react native apps https://github.com/infinitered/ignite
It seems like a good practice to have your screen code(jsx) separated from your container code (where you'll have your mapDispatchToProps and your mapStateToProps).
So a good 'flow of information' using redux would look something like this:
Screen + container -> (dispatch) -> actions -> (dispatch) -> reducers -> and then stored in the store.
So to give you an idea of how to implement this, I'll show an example on how to use it for your purpose.
LoginScreen.js
export default class LoginScreen extends Component {
constructor(props) {
super(props);
}
login() {
//Here i'm assuming that you have clicked some kind of button
//to submit the login information that you filled in your text input (username and password)
const { username, password } = this.props;
const loginData = {
username,
password
}
//here you'll be passing it to the dispatchToProps in your container
this.props.login(loginData)
}
}
LoginScreenContainer.js
const mapStateToProps = state => {
...state.userReducer,
}
const mapDispatchToProps = (dispatch) => {
//The function that you called on your screen,
//and then we'll be dispatching the loginData to the user_actions
login: (loginData) => {
dispatch(loginUser(loginData))
},
}
//Dont forget to connect both mapStateToProps and mapDispatchToProps to your screen
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
User_Actions.js
export function loginUser(loginData) {
//The code to login would be here, if you are using firebase,
//back4app or any other provider, you would implement the login required here
//Now assuming that the user successfully logged on you would dispatch a success and then store that user in the store
//(just as an example, you can store the username and any other information that you'd like):
if (user) {
dispatch({ type: 'USER_LOGIN', payload: { user } })
} else {
dispatch({ type: 'USER_LOGIN_REJECTED' });
}
}
User_Reducer.js this is your reducer, you can have reducers also to handle the navigation in your app (not recommended though). It's basically a giant switch case that you'll get the dispatch actions.
export default function reducer(state = {
user: null,
}, action) {
const { type, payload } = action
switch (type) {
case 'USER_LOGIN': {
return { ...state, user: payload.user }
}
case 'USER_LOGIN_REJECTED': {
return { ...state, user: null }
}
default: {
return state
}
}
}
Store.js
const rootReducer = combineReducers({
user_reducer,
})
let middleware = [thunk]
if (process.env.NODE_ENV !== 'production') {
middleware = [...middleware, logger] //Logger is an useful library to log your state changes
}
export default createStore(
rootReducer,
undefined,
applyMiddleware(...middleware)
)
App.js and then here you'll wrap your main stackNavigator in the provider tag
import { Provider } from 'react-redux';
import store from './src/redux/store';
render() {
return (
<Provider store={store}>
<RootNavigator />
</Provider>
)
}
Hopefully this helps you understand a basic flow (I'm sure there are other ways to do it) and how to implement redux for your needs.

React Native: Navigation not working in component

I can not open the third page screen with the On Press method in the List Component.js file. I do not understand the problem. I want to know what I'm doing wrong with this. Where is the problem? Thank you. Please help.
Thank you for your reply but this will not work, my friend. I've updated the ListComponent.js file. The ListComponent.js file is actually a list. Please can you look again. ?
App.js
import React, { Component } from 'react';
import {
WebView,
AppRegistry, StyleSheet, Text, View, Button
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import ListComponent from './ListComponent';
class App extends Component {
static navigationOptions =
{
title: 'App',
};
OpenSecondActivityFunction = () =>
{
this.props.navigation.navigate('Second');
}
render() {
return (
<View style={styles.container}>
<Button onPress = { this.OpenSecondActivityFunction } title = 'Open Second Activity'/>
</View>
);
}
}
class SecondActivity extends Component
{
static navigationOptions =
{
title: 'SecondActivity',
};
OpenThirdActivityFunction = () =>
{
this.props.navigation.navigate('Third');
}
render()
{
return(
<View style={{ flex: 1}}>
<ListComponents data={alapinCtrl} OpenThirdActivityFunction={this.OpenThirdActivityFunction} />
</View>
);
}
}
class ThirdActivity extends Component
{
static navigationOptions =
{
title: 'ThirdSecondActivity',
};
render()
{
return(
<View style={{ flex: 1}}>
<Text>3</Text>
</View>
);
}
}
export default ActivityProject = StackNavigator(
{
First: { screen: App },
Second: { screen: SecondActivity },
Third: { screen: ThirdActivity }
});
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},ActivityNameTextCss:
{
fontSize: 22,
color: 'black',
textAlign: 'center',
},
});
AppRegistry.registerComponent('ActivityProject', () => ActivityProject);
ListComponent.js
import React, { Component } from "react";
import {AppRegistry,View, Text, FlatList, ActivityIndicator} from "react-native";
import { List, ListItem, SearchBar } from "react-native-elements";
class ListComponents extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
seed: 1,
error: null,
refreshing: false
};
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "98%",
backgroundColor: "#CED0CE",
marginLeft: "2%"
}}
/>
);
};
renderHeader = () => {
return <SearchBar placeholder="Type Here..." lightTheme round />;
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
return (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.props.data}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={`${item.name}`}
subtitle={item.coders}
containerStyle={{ borderBottomWidth: 0 }}
onPress={() => this.props.OpenThirdActivityFunction(item.coders)}
/>
)}
keyExtractor={item => item.coders}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
/>
</List>
);
}
}
export default ListComponents;
Only SecondActivity has the navigation prop; you need to explicitly pass it to child component:
<ListComponent navigation={this.props.navigation} />
Alternatively,
<ListComponent onPress={() => this.props.navigation.navigate('Third')} />;
Then just do <Button onPress={this.props.onPress} in your ListComponent.