Cant get React native app to navigate to homescreen after facebook login - react-native

I am making a react native application where the user logs in with Facebook and then goes to their home page with more details of the app and I can not get the App to navigate to the homepage after successful login with Facebook.
I'm using React Navigator. I have been searching Stackoverflow for 3 days with no luck...
Any help would be appreciated
the homepage successfully navigated when using the regular button
as shown above but it will not after the facebook authentication
//index.js
import React, {
Component
} from 'react';
import {
Platform,
StyleSheet,
Image,
Button,
Slider,
Text,
View,
Dimensions
} from 'react-native';
import FBLoginButton from '../FBLoginButton';
import {
SliderBox
} from 'react-native-image-slider-box';
import {
SafeAreaView
} from 'react-navigation';
import A from 'react-native-a'
import {
NavigationActions,
StackActions
} from 'react-navigation';
import {
createStackNavigator,
createAppContainer
} from 'react-navigation';
//import App from '../App';
const FBSDK = require('react-native-fbsdk');
const {
LoginManager,
} = FBSDK;
let isLoggedIn = false
type Props = {};
export default class Login extends Component < Props > {
constructor(props) {
//this._loginAuth = this._loginAuth.bind(this)
super(props);
this.state = {
images: [
'https://hluhluwegamereserve.com/wp-content/uploads/2014/03/IMG_1579.jpg',
'https://static.independent.co.uk/s3fs-public/thumbnails/image/2019/04/26/09/giraffe.jpg',
]
};
}
//this.props.navigation.push('Home')
render() {
LoginManager.logInWithReadPermissions(['public_profile']).then(
function(result) {
if (result.isCancelled) {
alert('Login was cancelled');
} else {
alert('Login was successful with permissions: ' + result.grantedPermissions.toString());
//this.props.navigation.push('Home')
//this.props.navigation.navigate("Home")
//this._loginAuth()
}
},
function(error) {
alert('Login failed with error: ' + error);
}
);
//alert(this.state.loggedIn)
return (
<
View style = {
styles.container
} >
<
SliderBox style = {
styles.slider
}
images = {
this.state.images
}
sliderBoxHeight = {
'100%'
}
paginationBoxVerticalPadding = {
0
}
//parentWidth={400}
/>
<
Button onPress = {
() => this.props.navigation.navigate('Home')
}
title = "Go to Home"
color = "#841584" /
>
<
FBLoginButton onload = {
() => this.props.navigation.navigate('Home')
}
style = {
styles.welcome
} >
<
/FBLoginButton>
<
Text style = {
styles.instructions
} >
<
/Text>
<
/View>
);
}
}
if (this.isLoggedIn) {
this.props.navigation.navigate('Home')
}
// ...
// Attempt a login using the Facebook login dialog,
// asking for default permissions.
const styles = StyleSheet.create({
container: {
flex: 1,
//padding: 40,
//marginBottom: 250,
justifyContent: 'center',
alignItems: 'center',
//marginTop: '15%',
paddingTop: '15%',
paddingBottom: '15%',
resizeMode: 'contain',
},
slider: {
//width: '100%',
//alignSelf: 'flex-start',
//width: this.deviceWidth,
resizeMode: 'contain',
},
welcome: {
fontSize: 12,
textAlign: 'center',
marginBottom: '10%',
padding: '5%',
//paddingTop: 40,
},
terms: {
fontSize: 12,
color: 'blue',
textAlign: 'center',
margin: 1,
},
instructions: {
textAlign: 'center',
color: '#333333',
//marginBottom: 5,
},
safeArea: {
backgroundColor: '#ddd'
},
});
Here is my App.Js
//App.js
/*
* #format
* #flow
*/
import React, {
Component
} from 'react';
import {
Platform,
StyleSheet,
Image,
Button,
Slider,
Text,
View,
Dimensions
} from 'react-native';
import A from 'react-native-a'
import {
NavigationActions,
StackActions
} from 'react-navigation';
import {
createStackNavigator,
createAppContainer
} from 'react-navigation';
import HomeScreen from './screens/HomeScreen';
import Login from './screens/Login';
import {
StackNavigator
} from "react-navigation";
import FBLoginButton from './FBLoginButton'
type Props = {};
//Login Screen
const NavigationApp = createStackNavigator({
Login: Login,
Home: HomeScreen
}, {
initialRouteName: "Login"
});
class App extends Component < Props > {
constructor(props) {
super(props);
}
render() {
return (
//Empty View For App.js
<
View >
<
/View>
);
}
}
//Navagation Goes To Login.js For Default
export default createAppContainer(NavigationApp);

Instead of doing an if-statement in your code outside of your class, do this one:
Once you are logged-in, Facebook's LoginManager will be returning a Promise
The promise will then be checked. So, if you have
.then((result) => {
if(result) {
this.props.navigation.navigate('HomeScreen');
} else {
alert('...'); // Anything you want to do if login failed.
}
});

I used
FBLogout = (accessToken) => {
let logout =
new GraphRequest(
"me/permissions/",
{
accessToken: accessToken,
httpMethod: 'DELETE'
},
(error, result) => {
if (error) {
console.log('Error fetching data: ' + error.toString());
} else {
LoginManager.logOut();
}
});
new GraphRequestManager().addRequest(logout).start();
};
and added a button and used
LoginManager.logout();
<View style={styles.container}>
<SettingsView profile={this.state.profile}/>
<Button
onPress={() => {
FBLogout();
this.props.navigation.navigate('HomeScreen')
}}
title="Log Out"
color="#3b5998"
/>
</View>

Related

Not Navigating TO specific Screen in react native

I am New to react native :
I have created Two files "Browse.js" and "Drawer.js"
I have some Buttons in "Browse.js" But when I Wrap Up my Complete "Browse.js" in "Drawer.js"
like this:=>
import React, { Component } from "react";
import { Image, StyleSheet, ScrollView, TextInput, View } from "react-native";
import Slider from "react-native-slider";
import { AntDesign } from "#expo/vector-icons";
import { Foundation } from "#expo/vector-icons";
import { FontAwesome } from "#expo/vector-icons";
import { Ionicons } from "#expo/vector-icons";
import { MaterialCommunityIcons } from "#expo/vector-icons";
import { RoleLogin } from "./Browse";
import Browse from "./Browse";
import { createDrawerNavigator } from "#react-navigation/drawer";
import { NavigationContainer } from "#react-navigation/native";
import Login from "./Login"
import { Divider, Button, Block, Text, Switch } from "../components";
import { theme, mocks } from "../constants";
const Drawer = createDrawerNavigator();
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Browse" openByDefault>
<Drawer.Screen name="Browse" component={Browse} />
</Drawer.Navigator>
</NavigationContainer>
);
}
then I cant navigate To specific screen from here means from Drawer screen:
Showing error like this => The action 'NAVIGATE' with payload was not handled by any navigator.
Here Is My Browse.js
import React, { Component } from "react";
import {
Dimensions,
Image,
StyleSheet,
ScrollView,
TouchableOpacity,
View,
} from "react-native";
import { ThemeColors } from "react-navigation";
import { Card, Badge, Button, Block, Text } from "../components";
import { theme, mocks } from "../constants";
import Settings from "./Settings";
import { NotificationsScreen, App } from "./Settings";
const { width } = Dimensions.get("window");
const Drawer = createDrawerNavigator();
import { createDrawerNavigator } from "#react-navigation/drawer";
import { NavigationContainer } from "#react-navigation/native";
import Drawer1 from "./Settings";
import Home from "./Settings";
class Browse extends Component {
state = {
// active: "Products",
// active: "Select_Acivity",
categories: [],
error: [],
// data: [],
roles: "",
username: "",
password: "",
lading: false,
title: "",
data: "",
};
//++++++++++++++++++++++++++++++Drawer fun start++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++Drawer fun close++++++++++++++++++++++++++++++++++
//*******************navagte to setting when data fetch start*************************/
RoleLogin() {
// const { data } = this.state;
// const { username, password, roles } = this.state;
fetch(
"https://jsonplaceholder.typicode.com/todos/1",
//fetch(
// "https://nasdigital.tech/Android_API_CI/validate_login_details",
{
method: "GET",
headers: { "Content-Type": "application/json" },
// body: JSON.stringify([{ data}]),
}
)
.then((response) => response.json())
.then((json) => {
//login to check details from server and then display or navigate to another screen
if (json != "error") {
// if (response && response.length && response[0].message != "error")
alert(JSON.stringify(json));
this.props.navigation.navigate("Drawer", {
data: json.title,
});
// .navigate("Settings", { data: json.title });
// this.props.navigation.navigate("Settings",{data : json.title});
} else {
alert("Cehck Details");
}
})
.catch((error) => alert("Cehck Details"));
}
//*******************navagte to setting when data fetch close**************************** */
componentDidMount() {
this.setState({ categories: this.props.categories });
}
// handleTab = tab => {
// const { categories } = this.props;
// const filtered = categories.filter(category =>
// category.tags.includes(tab.toLowerCase())
// );
// this.setState({ active: tab, categories: filtered });
// };
renderTab(tab) {
const { active } = this.state;
const isActive = active === tab;
return (
<TouchableOpacity
key={`tab-${tab}`}
onPress={() => this.handleTab(tab)}
style={[styles.tab, isActive ? styles.active : null]}
>
<Text size={16} medium gray={!isActive} secondary={isActive}>
{tab}
</Text>
</TouchableOpacity>
);
}
render() {
const { profile, navigation } = this.props;
const { categories } = this.state;
// // const tabs = ["Products", "Inspirations", "Shop"];
// const tabs = ["Select_Activity", "Market_Visit"];
// const tabs = ["Select_Activity"];
const tabs = [""];
return (
<Block>
<Block flex={false} row center space="between" style={styles.header}>
<Text h1 bold>
Select Activity
</Text>
<Button onPress={() => this.RoleLogin()}>
<Image source={profile.avatar} style={styles.avatar} />
</Button>
{/* <Button onPress={() => navigation.navigate("Settings")}>
<Image source={profile.avatar} style={styles.avatar} />
</Button> */}
</Block>
<Block flex={false} row style={styles.tabs}>
{tabs.map((tab) => this.renderTab(tab))}
</Block>
<ScrollView
showsVerticalScrollIndicator={false}
style={{ paddingVertical: theme.sizes.base * 2 }}
>
<Block flex={false} row space="between" style={styles.categories}>
{categories.map((category) => (
<TouchableOpacity
key={category.name}
onPress={() => navigation.navigate("MarketVisit", { category })}
>
<Card center middle shadow style={styles.category}>
<Badge
margin={[0, 0, 15]}
size={90}
color="rgb(255, 163, 102)"
>
<Image source={category.image} />
</Badge>
<Text medium height={20}>
{category.name}
</Text>
<Text gray caption>
{category.count}
</Text>
</Card>
</TouchableOpacity>
))}
</Block>
</ScrollView>
</Block>
);
}
}
//+++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++
Browse.defaultProps = {
profile: mocks.profile,
categories: mocks.categories,
};
export default Browse;
const styles = StyleSheet.create({
header: {
paddingHorizontal: theme.sizes.base * 2,
},
avatar: {
height: theme.sizes.base * 1.0,
width: theme.sizes.base * 1.5,
},
tabs: {
borderBottomColor: theme.colors.gray2,
borderBottomWidth: StyleSheet.hairlineWidth,
marginVertical: theme.sizes.base,
marginHorizontal: theme.sizes.base * 2,
},
tab: {
marginRight: theme.sizes.base * 7,
paddingBottom: theme.sizes.base,
},
active: {
borderBottomColor: theme.colors.secondary,
borderBottomWidth: 3,
},
categories: {
flexWrap: "wrap",
paddingHorizontal: theme.sizes.base * 1.5,
marginBottom: theme.sizes.base * 2,
},
category: {
// this should be dynamic based on screen width
minWidth: (width - theme.sizes.padding * 2.4 - theme.sizes.base) / 2,
maxWidth: (width - theme.sizes.padding * 2.4 - theme.sizes.base) / 2,
maxHeight: (width - theme.sizes.padding * 2.4 - theme.sizes.base) / 2,
},
});
and here is my navigation file
import React from "react";
import { Image } from "react-native";
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { NavigationContainer } from "#react-navigation/native";
import { createDrawerNavigator } from "#react-navigation/drawer";
import Welcome from "../screens/Welcome";
import Login from "../screens/Login";
import SignUp from "../screens/SignUp";
import Forgot from "../screens/Forgot";
import Explore from "../screens/Explore";
// import Explore1 from "../screens/Explore1";
// import Explore2 from "../screens/Explore2";
// import Explore3 from "../screens/Explore3";
// import Explore4 from "../screens/Explore4";
// import Explore5 from "../screens/Explore5";
// import Explore6 from "../screens/Explore6";
// import Explore7 from "../screens/Explore7";
// import Explore8 from "../screens/Explore8";
import Browse from "../screens/Browse";
import Product from "../screens/Product";
//import Settings from "../screens/Settings";
import Drawer from "../screens/Drawer";
import MarketVisit from "../screens/MarketVisit";
import { theme } from "../constants";
const screens = createStackNavigator(
{
Welcome,
Login,
SignUp,
Forgot,
Explore,
Drawer,
//Browse,
//Product,
//Settings,
MarketVisit,
// NotificationsScreen,
// App,
},
{
defaultNavigationOptions: {
headerStyle: {
height: theme.sizes.base * 4,
backgroundColor: theme.colors.white, // or 'white
borderBottomColor: "transparent",
elevation: 0 // for android
},
// headerBackImage: <Image source={require("../assets/2.jpg")} />,
headerBackTitle: null,
headerLeftContainerStyle: {
alignItems: "center",
marginLeft: theme.sizes.base * 2,
paddingRight: theme.sizes.base
},
headerRightContainerStyle: {
alignItems: "center",
paddingRight: theme.sizes.base
}
}
}
);
export default createAppContainer(screens);

Fetching data from API in react native using redux

I am working on a react-native project where I am trying to fetch data from an api using axios library and display the data.So,my app first shows a splash screen and it then needs to navigate to a page which consists of tabs.The tabs will contain the data from the api.
So,I am trying to initialize my store in my Homepage which comes after the splash screen.I have my reducer and action defined separately in 2 different files.
App.js file
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import SplashScreen from './src/components/SplashScreen';
import HomeScreen from './src/components/HomeScreen';
const Navigation = StackNavigator({
Splash: {
screen: SplashScreen
},
Home: {
screen: HomeScreen
}
})
export default Navigation;
My SplashScreen component:
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
My HomeScreen component:
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
Action.js file
import axios from 'axios';
export const FETCH_DATA = 'fetch_data';
const API = 'https://api.myjson.com/bins/fz62x';
export function fetchData() {
const request = axios.get(API);
return dispatch => {
return request.then((data) => {
dispatch({
type: FETCH_DATA,
payload: data
})
})
}
}
My reducer
import { FETCH_DATA } from './actions';
export default function(state={}, action) {
switch(action.type) {
case FETCH_DATA:
return {
...state,
action.payload
};
default:
return state;
}
}
Can anyon please tell me if this the correct way? If not, then what is the correct way?
I would say there is no correct or incorrect way to do this. But I can share kind of a pattern that I usually use.
First I would create separate folders for different files. Actions in actions folder, reducers in reducers folder etc... I would create separate constants.js file and configureStore.js file and put them inside the project root directory.
I would drop Axios library and would just use Fetch API for data fetching. Considering your code I would do the following.
Create configureStore.js file inside your project root directory. I recommend you to use Redux-Thunk. You can find more info from here.
configureStore.js
import { createStore, applyMiddleware } from 'redux';
import app from './reducers';
import thunk from 'redux-thunk';
export default function configureStore() {
let store = createStore(app, applyMiddleware(thunk))
return store
}
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { StackNavigator } from 'react-navigation';
import configureStore from './configureStore';
import HomeScreen from './screens/HomeScreen';
const NavigationApp = StackNavigator({
HomeScreen: { screen: HomeScreen }
})
const store = configureStore()
export default class App extends Component {
render() {
return (
<Provider store={store}>
<NavigationApp />
</Provider>
);
}
}
Let's create constants.js and we place it inside the project root directory.
constants.js
export const FETCHING_TODOS = 'FETCHING_TODOS';
export const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS';
export const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE';
Now let's move on and create our action file which would be put inside the actions folder. Let's name it something like fetchToDos.js. Let's create a simple function using Fetch API.
fetchToDos.js
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
export function fetchToDos() {
return (dispatch) => {
dispatch(getTodos())
return(fetch('https://api.myjson.com/bins/fz62x'))
.then(res => res.json())
.then(json => {
return(dispatch(getToDosSuccess(json)))
})
.catch(err => dispatch(getToDosFailure(err)))
}
}
function getToDos() {
return {
type: FETCHING_TODOS
}
}
function getToDosSuccess(data) {
return {
type: FETCH_TODOS_SUCCESS,
data
}
}
function getToDosFailure() {
return {
type: FETCH_TODOS_FAILURE
}
}
fetchToDos.js with Axios
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
import axios from 'axios';
export function fetchToDos() {
return (dispatch) => {
dispatch(getUser())
axios.get('https://api.myjson.com/bins/fz62x')
.then(function (response) {
// handle your response here, create an object/array/array of objects etc...
// and return it in dispatch(getToDosSuccess(data over here))
return(dispatch(getToDosSuccess(response.data)))
})
.catch(err => dispatch(getToDosFailure(err)))
}
}
// rest is the same...
Moving on to reducers. Let's create two files - index.js, todos.js and put them inside reducers folder.
todos.js
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
const initialState = {
todos: [],
isFetching: false,
error: false
}
export default function todosReducer(state = initialState, action) {
switch(action.type) {
case FETCHING_TODOS:
return {
...state,
isFetching: true
}
case FETCH_TODOS_SUCCESS:
return {
...state,
isFetching: false,
todos: action.data
}
case FETCH_TODOS_FAILURE:
return {
...state,
isFetching: false,
error: true
}
default:
return state
}
}
index.js
import { combineReducers } from 'redux';
import todos from './todos';
const rootReducer = combineReducers({
todos
})
export default rootReducer
Basically "heavy lifting" is done. I would only create one screen because let's assume that users would tap back button (Android) while at home screen, they would end up on that splash screen. So in this example I am going to use one screen only.
HomeScreen.js
import React, { Component } from 'react';
import {
View,
Text,
ActivityIndicator
} from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { fetchTodos } from '../actions/fetchTodos';
class HomeScreen extends Component {
componentDidMount() {
this.props.fetchTodos()
}
render() {
const { todos, isFetching } = this.props.todos
if (isFetching) {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<ActivityIndicator size={'large'} />
</View>
)
} else {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<Text>todos.length</Text>
</View>
)
}
}
}
function mapStateToProps(state) {
return {
todos: state.todos
}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ fetchTodos }, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen)
I really hope that you find this concept useful because I can say from my experience that it helped me a lot when I first get started and it helped me to understand the whole concept of redux much better.
Sorry if there are any typos and errors. I was on a flow.

react native navigation Could not find "store" in either the context or props of "Connect(facebookLogin)

I'm building react native app authentication with facebook login.
I'm using stack navigator and I want to add redux to my app.
I just seperate my files to components and when I use stack navigation with redux I get this error
Could not find "store" in either the context or props of
"Connect(facebookLogin)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(facebookLogin)".
index.android.js
import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, AppRegistry, Image } from 'react-native';
import facebookLogin from './src/components/FacebookLogin';
import Home from './src/components/Home';
import {
StackNavigator,
} from 'react-navigation';
const App = StackNavigator({
Home: { screen: facebookLogin },
HomePage: {screen:Home},
})
AppRegistry.registerComponent('facebookLogin', () => App);
FacebookLogin.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, AppRegistry, Image } from 'react-native';
import FBSDK, { LoginManager, GraphRequest, GraphRequestManager } from 'react-native-fbsdk';
import Icon from 'react-native-vector-icons/FontAwesome';
// redux
import { Provider } from 'react-redux';
import { connect } from 'react-redux';
import { createStore } from 'redux';
import reducers from '../reducers/ProfileReducers';
const store = createStore(reducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
class facebookLogin extends Component {
constructor(props) {
super(props);
this.state = {
result: null
}
}
_fbAuth() {
const { navigate } = this.props.navigation;
LoginManager.logInWithReadPermissions(['public_profile','user_birthday']).then((result) => {
if (result.isCancelled) {
console.log('Login was canclled');
}
else {
console.log(result);
const infoRequest = new GraphRequest(
'/me?fields=id,name,picture.width(800).height(800),gender,birthday,first_name,last_name',
null,
(error, result) => {
if (error) {
alert('Error fetching data: ' + error.toString());
} else {
console.log(result);
this.setState({ result });
navigate('HomePage');
}
}
);
// Start the graph request.
new GraphRequestManager().addRequest(infoRequest).start();
}
}, function (error) {
console.log('An error occured:' + error);
})
}
getProfileData() {
const { ImageStyle } = styles;
if (this.state.result) {
return (
<View>
{this.state.result.picture ? <Image style={ImageStyle} source={{ uri: this.state.result.picture.data.url }}></Image> : null}
<Text> first name: {this.state.result.first_name} </Text>
<Text> Last name: {this.state.result.last_name} </Text>
<Text> Gender {this.state.result.gender} </Text>
</View>
)
}
return null;
}
render() {
return (
<Provider store = {store}>
<View style={styles.container}>
<Icon.Button name="facebook" backgroundColor="#3b5998" onPress={() => { this._fbAuth() }}>
<Text style={{fontFamily: 'Arial', fontSize: 15, color:'white'}}>Login with Facebook</Text>
</Icon.Button>
{this.getProfileData()}
</View>
</Provider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
ImageStyle:{
borderRadius:80,
width:100,
height:100
}
});
const mapStateToProps = (state) => {
return
{ profile: state.profile};
}
export default connect(mapStateToProps)(facebookLogin);
when it was only one component in index.android.js it works fine without any error but when I seperate it to some components using stack navigation I get this error.
my profileReducers
var profile = {
name :'',
email:'',
photo:''
}
const initialState = {
profile,
};
export default (state = initialState, action) => {
console.log("state");
switch (action.type) {
case 'INSERT_PROFILE_DETAILS':
return {
profile: action.payload
}
case 'GET_PROFILE_DETAILS': {
return state;
}
default:
return state;
}
}
Try setting up redux in index.android.js instead so it looks something like this:
// Set up redux store above
const Navigator = StackNavigator({
Home: { screen: facebookLogin },
HomePage: { screen: Home },
});
const App = () => (
<Provider store={store}>
<Navigator />
</Provider>
);
AppRegistry.registerComponent('facebookLogin', () => App);

React Native Auth with React Navigation and Redux

I have just started integrating Redux into my first React Native (Expo.io) project. I have got login working great with Redux, but when I try and create a logout button on one of the screens in my app, it actually triggers the log out dispatch as soon as it loads it. I think I must be misunderstanding the way Redux connect and mapDispatchToProps work. I have read the documentation many times but am still stuck. Here is the code in it's non-working state.
Log In - Works until I add the log out dispatch on profile page
import { connect } from "react-redux";
import React, { Component } from "react";
import {
Button,
View,
Text,
ActivityIndicator,
Alert,
FlatList
} from "react-native";
import { NavigationActions } from "react-navigation";
import { SocialIcon, Card } from "react-native-elements";
import Reactotron from "reactotron-react-native";
import { logIn } from "../actions";
import { signIn } from "../components/Auth";
class SignIn extends Component {
async handleClick() {
res = await signIn();
if (res != false) {
this.props.logIn(res.token);
} else {
console.log("Login Failed");
}
}
render() {
return (
<View style={{ paddingVertical: 20 }}>
<Card title="finis Requires A Facebook Account To Operate">
<SocialIcon
title="Fred"
button
type="facebook"
onPress={() => this.handleClick()}
/>
</Card>
</View>
);
}
}
const mapDispatchToProps = dispatch => {
return {
logIn: fbToken => {
dispatch(logIn(fbToken));
}
};
};
LoginScreen = connect(null, mapDispatchToProps)(SignIn);
export default LoginScreen;
Reducers
import { combineReducers } from "redux";
import Reactotron from "reactotron-react-native";
import { LOG_IN, LOG_OUT, ADD_PHONE_CONTACTS } from "../actions/actions";
const initialState = {
signedIn: false,
fbToken: "fred",
test: undefined,
phoneContacts: {}
};
const finis = combineReducers({
auth,
phoneContacts
});
function auth(state = initialState, action) {
switch (action.type) {
case LOG_IN:
Reactotron.log("LOG IN");
return {
...state,
signedIn: true,
fbToken: action.fbToken
};
case LOG_OUT:
Reactotron.log("LOG OUT");
return {
...state,
signedIn: false,
fbToken: undefined
};
default:
return state;
}
}
function phoneContacts(state = [], action) {
switch (action.type) {
case ADD_PHONE_CONTACTS:
console.log("Adding Contacts");
return {
...state,
phoneContacts: action.phoneContacts
};
default:
return state;
}
}
export default finis;
Profile Non working. Triggers LOG_OUT action without the button being pushed.
import React, { Component } from "react";
import { Button, Card } from "react-native-elements";
import { View, Text, ActivityIndicator, AsyncStorage } from "react-native";
import { MapView } from "expo";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { SimpleLineIcons } from "#expo/vector-icons";
import Reactotron from "reactotron-react-native";
import * as ActionCreators from "../actions";
import { signOut } from "../components/Auth";
class ProfileWrap extends Component {
handleClick() {
Reactotron.log(this.Actions);
this.props.logOut();
}
render() {
return (
<View style={{ paddingVertical: 20 }}>
<Card title="Profile">
<View
style={{
backgroundColor: "#bcbec1",
alignItems: "center",
justifyContent: "center",
width: 80,
height: 80,
borderRadius: 40,
alignSelf: "center",
marginBottom: 20
}}
>
<Text style={{ color: "white", fontSize: 28 }}>JD</Text>
</View>
<Button title="Log Out" onPress={this.handleClick} />
</Card>
</View>
);
}
}
mapDispatchToProps = dispatch => {
return {
logOut: dispatch(logOut())
};
};
const Profile = connect(null, mapDispatchToProps)(ProfileWrap);
export default Profile;
Any help would be appreciated, even if it's telling me I'm doing the whole thing wrong :) Been at this for hours.
NEW Profile.js - Gives Cannot read property 'logOut' of undefined
import React, { Component } from "react";
import { Button, Card } from "react-native-elements";
import { View, Text, ActivityIndicator, AsyncStorage } from "react-native";
import { MapView } from "expo";
import { connect } from "react-redux";
import { SimpleLineIcons } from "#expo/vector-icons";
import { logOut } from "../actions";
import { signOut } from "../components/Auth";
class ProfileWrap extends Component {
handleClick() {
console.log(this.props);
this.props.logOut();
}
render() {
return (
<View style={{ paddingVertical: 20 }}>
<Card title="Profile">
<View
style={{
backgroundColor: "#bcbec1",
alignItems: "center",
justifyContent: "center",
width: 80,
height: 80,
borderRadius: 40,
alignSelf: "center",
marginBottom: 20
}}
>
<Text style={{ color: "white", fontSize: 28 }}>JD</Text>
</View>
<Button title="Log Out" onPress={this.handleClick} />
</Card>
</View>
);
}
}
const mapDispatchToProps = dispatch => {
return {
logOut: function() {
dispatch(logOut());
}
};
};
const Profile = connect(null, mapDispatchToProps)(ProfileWrap);
export default Profile;
Your mapDispatchToProps should be returning an object with functions. The way you have it now, logOut() will be called immediately since it's not inside a function. Changing it to this should fix it:
const mapDispatchToProps = dispatch => {
return {
logOut: function () {
dispatch(logOut());
}
};
};
Here's a slightly cleaner way of doing it:
const mapDispatchToProps = dispatch => ({
logOut() {
dispatch(logOut());
}
});
Also, you're missing const in front of mapDispatchToProps but that shouldn't have affected anything.
Edit:
You don't have to use this now, but it'll be helpful in the future - if your component is only using the render method you can change it to a stateless functional component. It's currently the recommended way of creating components when possible:
const ProfileWrap = props => (
<View style={{ paddingVertical: 20 }}>
<Card title="Profile">
<View
style={{
backgroundColor: "#bcbec1",
alignItems: "center",
justifyContent: "center",
width: 80,
height: 80,
borderRadius: 40,
alignSelf: "center",
marginBottom: 20
}}
>
<Text style={{ color: "white", fontSize: 28 }}>JD</Text>
</View>
<Button title="Log Out" onPress={props.logOut} />
</Card>
</View>
);

How to fix React Native Element type is invalid: expected a string or a class/function but got object issue?

I would try to implement react-native-push-notification :
Here is my code :
index.android.js :
import React from 'react';
import { AppRegistry } from 'react-native';
import App from './app';
AppRegistry.registerComponent('PushNotificationHowTo', () => App);
/app/index.js
import React, { Component } from 'react';
import { View, Text, StyleSheet, Picker, AppState, Platform } from 'react-native';
import PushController from './PushController';
import PushNotification from 'react-native-push-notification';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
picker: {
width: 100,
},
});
export default class App extends Component {
constructor(props) {
super(props);
this.handleAppStateChange = this.handleAppStateChange.bind(this);
this.state = {
seconds: 5,
};
}
componentDidMount() {
AppState.addEventListener('change', this.handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
}
handleAppStateChange(appState) {
if (appState === 'background') {
let date = new Date(Date.now() + (this.state.seconds * 1000));
if (Platform.OS === 'ios') {
date = date.toISOString();
}
PushNotification.localNotificationSchedule({
message: "My Notification Message",
date,
});
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Choose your notification time in seconds.
</Text>
<Picker
style={styles.picker}
selectedValue={this.state.seconds}
onValueChange={(seconds) => this.setState({ seconds })}
>
<Picker.Item label="5" value={5} />
<Picker.Item label="10" value={10} />
<Picker.Item label="15" value={15} />
</Picker>
<PushController />
</View>
);
}
}
/app/PushController.js
import React, { Component } from 'react';
import PushNotification from 'react-native-push-notification';
export default class PushController extends Component {
componentDidMount() {
PushNotification.configure({
onNotification: function(notification) {
console.log( 'NOTIFICATION:', notification );
},
});
}
render() {
return null;
}
}
While execute the code i got below the Issue :
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
How to fix that issue and how to implement push notifications ??