How do I add Redux implementation in my code? - react-native

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.

Related

Problem accessing navigation parameters in consuming component

I am having difficulty of accessing parameters passed from component named NewsPageScreen.js. the parameters are passed to BrowserScreen.js. My app has Main Navigator component called MainTabNavigator.js that displays Bottom Tabs. The 'News' tab is connected to NewsPageScreen.js and this is where I am passing the the parameter to BrowserScreen.js but for some reason I am unable to access the parameters BrowserScreen.js, Can anyone help me see what I am getting wrong because it is giving me undefined. All my files are shown below:
MainTabNavigator.js
import React from 'react';
import { Ionicons } from '#expo/vector-icons';
import { TabBarBottom } from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs'
import { createAppContainer } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import NewsPageScreen from '../screens/NewsPageScreen';
import FavouriteScreen from '../screens/FavouriteScreen';
import SettingScreen from '../screens/SettingScreen';
import BrowserScreen from '../screens/BrowserScreen';
const Colors = {
tabIconDefault: '#ccc',
tabIconSelected: '#2f95dc'
}
const tabNavigator = createBottomTabNavigator({
News: createStackNavigator({
News: NewsPageScreen,
navigationOptions: ({ navigation }) => ({
title: 'News'
}),
}),
Favourite: createStackNavigator({
Favourite: FavouriteScreen,
navigationOptions: ({ navigation }) => ({
title: 'Favourite'
}),
}),
Setting: createStackNavigator({
Setting: SettingScreen,
navigationOptions: ({ navigation }) => ({
title: 'Setting'
}),
}),
Browser: createStackNavigator({
Browser: BrowserScreen,
navigationOptions: ({ navigation }) => ({
title: navigation.state.params.title
}),
}),
}, {
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons ;
let iconName;
switch (routeName) {
case 'News':
//iconName = `ios-information-circle`;
iconName = focused ? 'ios-information-circle' : 'ios-information-circle-outline'
break;
case 'Favourite':
iconName = `ios-link`;
break;
case 'Setting':
iconName = `ios-options`;
}
return
<IconComponent
name={iconName}
size={28}
style={{marginBottom: -3}}
//color={tintColor}
color={focused ? Colors.tabIconSelected : Colors.tabIconDefault}
/>
},
}),
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
});
const MainTabNavigator = createAppContainer(tabNavigator)
export default MainTabNavigator;
NewsPageScreen.js
import React, { Component } from 'react'
import { TouchableOpacity, View,StyleSheet,Text,SafeAreaView,} from 'react-native';
export default class NewsPageScreen extends Component {
state = {
links: [
{
title: 'Smashing Magazine',
url: 'https://www.smashingmagazine.com/articles/'
},
{
title: 'CSS Tricks',
url: 'https://css-tricks.com/'
},
],
};
handleButtonPress = (button) => {
const { url, title } = button;
this.props.navigation.navigate('BrowserScreen', { url, title });
}
renderButton = (button, index) => {
return (
<TouchableOpacity
key={index}
onPress={() => this.handleButtonPress(button)}
style={styles.button}
>
<Text style={styles.text}>{button.title}</Text>
</TouchableOpacity>
);
}
render() {
return (
<SafeAreaView style={styles.container}>
<View>
<Text style={styles.newsTitle}>Scan The Somali world News</Text>
</View>
<View style={styles.buttonList}>
{this.state.links.map(this.renderButton)}
</View>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
buttonList: {
flex: 1,
justifyContent: 'center',
},
button: {
margin: 10,
backgroundColor: '#c0392b',
borderRadius: 3,
padding: 10,
paddingRight: 30,
paddingLeft: 30,
},
text: {
color: '#fff',
textAlign: 'center',
},
newsTitle: {
color:'#000',
textAlign: 'center',
marginTop: 20
}
});
BrowserScreen.js
import React, { Component } from 'react'
import { WebView } from 'react-native-webview';
export default class BrowserScreen extends Component {
render() {
//console.log(navigation)
const { params } = this.props.navigation.state;
console.log(params)
return (
/**
* use the webview here to display the webpage
*/
<WebView source={{ uri: url }} />
)
}
}
App.js
import { StatusBar } from 'expo-status-bar';
import React, { useState } from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import AppIntroSlider from "react-native-app-intro-slider";
import MainTabNavigatorp from './src/navigation/MainTabNavigator';
export default function App() {
return (
<View style={{flex: 1}}>
<MainTabNavigator />
</View>
);
}
const styles = StyleSheet.create({
MainContainer: {
flex: 1,
paddingTop: 20,
alignItems: 'center',
justifyContent: 'center',
padding: 20
},
slide: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'blue',
},
image: {
width: 220,
height: 220,
marginVertical: 32,
},
description: {
color: 'rgba(255, 255, 255, 0.8)',
textAlign: 'center',
paddingLeft: 10,
paddingRight: 10,
fontSize: 18,
},
title: {
fontSize: 25,
color: 'white',
fontWeight: 'bold',
textAlign: 'center',
},
});

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;

this.props.navigation.navigate does not work in screen

In my app I have a choose language screen which I have registered in the stackNavigator but I cannot use this.props.navigation.navigate in it
this 'choose language screen' appears on app first launch
this is index.js
import {AppRegistry} from 'react-native';
import App from './App';
import ChooseLanguage from './screens/ChooseLanguage'
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => ChooseLanguage);
this is ChooseLanguage Screen so when pressing the touchable opacity
I am calling this.props.navigation.navigate('AppIntroScreen') but it is not working it is giving me this error:
undefined is not an object (evaluating _this2.props.navigation.navigate)
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
Image, SafeAreaView, TouchableOpacity,AsyncStorage
} from "react-native";
import {withNavigation} from 'react-navigation'
import i18n from 'i18next';
import { translate } from 'react-i18next';
import NavigationService from './NavigationService';
import AppIntroScreen from './AppIntroScreen'
class ChooseLanguage extends Component {
state = {
isArabic: false,
isEnglish: false,
switchLang: true,
languageSet:false
}
async onChangeLang(lang) {
i18n.changeLanguage(lang);
try {
await AsyncStorage.setItem('#APP:languageCode', lang);
} catch (error) {
console.log(` Hi Errorrrr : ${error}`);
}
console.log(i18n.dir());
this.setState(state => ({
switchLang: !state.switchLang,
}));
}
render() {
const {t,navigation} = this.props;
console.log(navigation)
return (
(this.state.switchLang ? <SafeAreaView style={styles.container}>
<Image source={require('../assets/lang.png')} />
<Text style={{ fontSize: 25, color: '#FF5252', marginTop: 20, fontFamily: 'Hanken-Book' }}>Choose Language</Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-evenly' }}>
<TouchableOpacity onPress={() => this.setState({ isEnglish: true, isArabic: false })} style={{ marginVertical: 20, marginHorizontal: 20, padding: 10, borderBottomColor: this.state.isEnglish ? '#a8a8a8' : '#ffffff', borderBottomWidth: this.state.isEnglish ? 1 : 0 }}>
<Text style={{color:this.state.isEnglish?'#000000':'#A8A8A8'}}>English</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setState({ isEnglish: false, isArabic: true })} style={{ marginVertical: 20, marginHorizontal: 20, padding: 10,borderBottomColor: this.state.isArabic ? '#a8a8a8' : '#ffffff', borderBottomWidth: this.state.isArabic ? 1 : 0 }}>
<Text style={{color:this.state.isArabic?'#000000':'#A8A8A8'}}>Arabic</Text>
</TouchableOpacity>
</View>
<TouchableOpacity onPress={() =>
{
if(this.state.isArabic){
this.onChangeLang('ar');
this.props.navigation.navigate('AppIntroScreen');
}else if(this.state.isEnglish){
this.onChangeLang('en');
this.props.navigation.navigate('AppIntroScreen');
}else{
alert('Please Choose a language')
}
}
} style={{ backgroundColor: '#FF5252', alignSelf: 'center', padding: 10, width: '40%', marginTop: 15,borderRadius:5 }}>
<Text style={{ color: '#FFF', fontSize: 18, fontWeight: '100', textAlign: 'center', fontFamily: 'Hanken-Book' }}>Let's Start</Text>
</TouchableOpacity>
<View style={{
position: 'absolute',
bottom: 0,
right: 1,
left: 1,
height: 50,
justifyContent: 'center', alignItems: 'center'
}}>
<Image source={require('../assets/l1.png')} style={{ width: 120, height: 25 }} />
</View>
</SafeAreaView>:<AppIntroScreen />)
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
bottom: 20
}
});
export default translate(['chooselanguage'], { wait: true })(ChooseLanguage);
even though I am registering all my screens in the StackNavigator
here is the code of App.js
const TabNav = createBottomTabNavigator({
HomeScreen: {
screen: HomeScreen,
},
Categories: {
screen: Categories,
},
Search: {
screen: Search,
},
Settings: {
screen: Settings,
},
}, {
tabBarOptions: {
activeTintColor: '#ff5252',
inactiveTintColor: 'grey',
style: {
backgroundColor: 'white',
borderTopWidth: 0,
shadowOffset: { width: 5, height: 3 },
shadowColor: 'black',
shadowOpacity: 0.5,
elevation: 5
}
}
})
const StacksOverTabs = createStackNavigator({
Root: {
screen: TabNav,
},
ChooseLanguage:{
screen: ChooseLanguage,
navigationOptions:{
}
},
ListingPerCategory: {
screen: ListingPerCategory,
navigationOptions: {
// title: 'Notifications',
},
},
ListingInformation: {
screen: ListingInformation,
navigationOptions: {}
},
SubscribeScreen: {
screen: SubscribeScreen,
navigationOptions: {}
},
AppIntroScreen: {
screen: AppIntroScreen,
navigationOptions: {}
},
OnboardingScreens: {
screen: OnboardingScreens,
navigationOptions: {}
},
ListingDetail: {
screen: ListingDetail,
navigationOptions: {}
},
Contact: {
screen: ContactScreen,
navigationOptions: {}
},
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false,
}
});
const WrappedStack = ({ t,navigation }) => {
return <StacksOverTabs screenProps={{ t,navigation}} />;
};
const ReloadAppOnLanguageChange = translate('common', {
bindI18n: 'languageChanged',
bindStore: false,
})(WrappedStack);
class App extends React.Component {
state = { notification: {}, timePassed: false }
componentDidMount() {
OneSignal.init('99471d55-8e89-49ef-a70f-47661c9f952b', { kOSSettingsKeyAutoPrompt: true })
OneSignal.addEventListener('received', this.onReceived);
OneSignal.addEventListener('opened', this.onOpened);
OneSignal.addEventListener('ids', this.onIds);
}
async retrieveItem(key) {
try {
const retrievedItem = await AsyncStorage.getItem(key);
const item = JSON.parse(retrievedItem);
return item;
} catch (error) {
console.log("error");
}
return
}
componentWillUnmount() {
OneSignal.removeEventListener('received', this.onReceived);
OneSignal.removeEventListener('opened', this.onOpened);
OneSignal.removeEventListener('ids', this.onIds);
}
onReceived(notification) {
console.log("Notification received: ", notification);
}
onOpened(openResult) {
console.log('Message: ', openResult.notification.payload.body);
console.log('Data: ', openResult.notification.payload.additionalData);
console.log('isActive: ', openResult.notification.isAppInFocus);
console.log('openResult: ', openResult);
}
onIds(device) {
console.log('Device info: ', device);
}
render() {
this.retrieveItem('appLaunched').then((goals) => {
console.log(goals)
}).catch((error) => {
//this callback is executed when your Promise is rejected
console.log('Promise is rejected with error: ' + error);
});
return <ReloadAppOnLanguageChange />
}
}
export default App;
You can access the navigation prop in any component(deeply nested) by composing withNavigation HOC (not available in v1). It's useful when you cannot pass the navigation prop into the component directly, or don't want to pass it in case of a deeply nested child.
import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';
class MyBackButton extends React.Component {
render() {
return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
}
}
// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);

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

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;