react native updating redux store from app.js not working - react-native

https://snack.expo.io/#mparvez19861/redux-example
I have below code in app.js in
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import firebase from './FireBaseSetup/Firebase'
// import DrawerNavigatorExample from './Navigations';
import Navigator from './Navigator'
import Permissions from 'react-native-permissions'
import { PermissionsAndroid } from 'react-native';
import PermissionsList from './Utitliy/PermissionsList'
import Contacts from 'react-native-contacts';
import { Provider, connect } from 'react-redux';
import { store, persistor, setCurrentLocation } from './redux/app-redux';
import { PersistGate } from 'redux-persist/integration/react'
import SplashScreen from './screens/SplashScreen'
const mapDispatchToProps = (dispatch) => {
return {
setCurrentLocation: (location) => { dispatch(setCurrentLocation(location)) }
};
}
const ConnectedApp = connect(mapDispatchToProps)(Navigator);
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
error: null,
};
}
async componentDidMount() {
this.getContacts();
await new PermissionsList().requestLocationPermission();
Geolocation.getCurrentPosition(
(position) => {
// this.setState({
// latitude: position.coords.latitude,
// longitude: position.coords.longitude,
// error: null,
// });
this.props.setCurrentLocation(position);
firebase.firestore().collection('locations').doc('8686').set({
locations: position
})
},
(error) => alert(JSON.stringify(error)),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000, distanceFilter: 100 }
);
this.watchId = Geolocation.watchPosition(
(position) => {
// this.setState({
// latitude: position.coords.latitude,
// longitude: position.coords.longitude,
// error: null,
// });
this.props.setCurrentLocation(position);
firebase.firestore().collection('locations').doc('8686').set({
locations: position
})
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: false, timeout: 20000, maximumAge: 10000, distanceFilter: 1 },
);
}
componentWillUnmount() {
Geolocation.clearWatch(this.watchId);
}
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<View style={styles.container}>
<ConnectedApp />
</View>
</PersistGate>
</Provider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
});
Navigator.js
import React, { Component } from 'react';
import { View, Text, TouchableHighlight, Image } from 'react-native';
import { createDrawerNavigator, createStackNavigator , createSwitchNavigator, createAppContainer } from 'react-navigation';
import {
ActivityIndicator,
AsyncStorage,
Button,
StatusBar,
StyleSheet
} from 'react-native';
// import firebase from 'react-native-firebase';
// import { store } from '../redux/app-redux';
import Screen2 from './screens/Screen2';
import SplashScreen from './screens/SplashScreen'
import Login from './screens/Login'
import SignOutScreen from './screens/SignOutScreen'
import screendesign from './screens/screendesign'
import EmailPwdLogin from './screens/EmailPwdLogin'
import friends from './screens/friends'
import LoginScreen from './screens/LoginScreen';
import SignupScreen from './screens/SignupScreen';
const AuthStack = createStackNavigator({
// { SignIn: SignInScreen }
// SignIn: { screen: EmailPwdLogin }
Login: { screen: Login },
Signup: { screen: SignupScreen },
});
const drNav = createDrawerNavigator(
{
friends: {
screen: friends
},
Screen2: {
screen: Screen2
},
SignOut: {
screen: SignOutScreen
}
}
)
export default createAppContainer(createSwitchNavigator(
{
// screendesign: screendesign,
SplashScreen: SplashScreen,
App: drNav,
AuthStack: AuthStack
},
{
initialRouteName: 'SplashScreen',
}
));
Redux file
const setCurrentLocation = (location) => {
alert(JSON.stringify(location))
return {
type: "setCurrentLocation",
value: location
};
};
export { setCurrentLocation };
But this setCurrentLocation is not being fired from app.js
please help.
Thanks

You are trying to dispatch a redux action from App.js which is the entry point of your application and where you initialise your redux store. You can use this.props.setCurrentLocation(position) from any connected component within the Provider component, but App.js is outside of it.
So you need to call it like so:
store.dispatch(setCurrentLocation(position))
I tried to run your snack to see if you have any other issues but it throws an error.
Hope this helps

You forget to connect mapDispatchToProps:
export default connect(mapStateToProps,mapDispatchToProps)(App);

Related

Import a font in React Native

I hope you can help me... I'm looking to the different discussions about it but nothing seems to work for me... It's really weird.
I want to custom the font of my app. I choose Parisienne as font for my titles. I downloaded he font into my "assets/font" folder. My App.js is here but It doesn't work as in Expo tutorial... App.js is just the door for DrawerNavigator.
Is anyone able to help me ? Thanks a lot !
import React, { Component } from "react";
import { View } from "react-native";
import styles from "./assets/Styles";
import DrawerNavigator from "./Drawer/DrawerNavigator";
import * as Font from "expo-font";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
fontLoaded: false
};
}
async componentDidMount() {
await Font.loadAsync({
Parisienne: require("./assets/fonts/Parisienne/Parisienne.ttf")
});
this.setState({ fontLoaded: true });
}
render() {
if ((this.state.fontLoaded = true)) {
return <DrawerNavigator />;
} else {
return null;
}
}
}
DrawerNavigator.js :
import React from "react";
import {
Image,
Platform,
Dimensions,
StyleSheet,
Text,
View
} from "react-native";
import { createDrawerNavigator } from "react-navigation-drawer";
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import Actus from "../Components/Actus/Actus";
import Carte from "../Components/Carte/Carte";
import Reservation from "../Components/Reservation/Reservation";
import Restaurant from "../Components/Restaurant/Restaurant";
import Vins from "../Components/Vins/Vins";
import Acces from "../Components/Acces/Acces";
import Newsletter from "../Components/Newsletter/Newsletter";
import Welcome from "../Components/Welcome/Welcome";
// import Settings from "../Components/Settings/Settings"
import MenuDrawer from "./MenuDrawer"
import Slider from "../Components/Slider/Slider";
const WIDTH = Dimensions.get("window").width;
const DrawerConfig = {
drawerWidth: WIDTH * 0.35,
contentComponent: ({ navigation }) => {return (<MenuDrawer navigation = {navigation} />)}
};
const DrawerNavigator = createDrawerNavigator(
{
Welcome: {
screen: Welcome
},
Actus: {
screen: Actus
},
Carte: {
screen: Carte
},
Reservation: {
screen: Reservation
},
Restaurant: {
screen: Restaurant
},
Vins: {
screen: Vins
},
Acces: {
screen: Acces
},
Newsletter: {
screen: Newsletter
},
Slider: {
screen: Slider
}
},
DrawerConfig
);
export default createAppContainer(DrawerNavigator);
The Error :
console.error : "fontFamily "Parisienne" is not a system font and has
not been loaded through Font.loadAsync.
I just saw you have huge error in your render function
render() {
// here shouldn't be = true
if ((this.state.fontLoaded = true)) {
return <DrawerNavigator />;
} else {
return null;
}
}
You shoud change it to
render() {
// correct way of checking bool value
if (this.state.fontLoaded) {
return <DrawerNavigator />;
} else {
return null;
}
}
The problem here is that this.state.fontLoaded = true will always return true and it will load the component before loading the font, causing the error.

React Native Navigation Root issue with multiple views

Hello All I am facing an issue.
I am trying to set different root in app.js file but it always open Home View. Can anyone tell me what is wrong with my code. Any help would be highly appreciable!
import React, { Component } from "react";
import { View, Text, AsyncStorage, AppRegistry } from "react-native";
import LoginContainer from "./Login/LoginContainer";
import { createStackNavigator, createAppContainer } from "react-navigation";
import Home from "./Dashboard/Home";
const RootStack = createStackNavigator(
{
login: { screen: LoginContainer },
Home: { screen: Home }
},
{
initialRouteName: "login"
}
);
const AppContainer = createAppContainer(RootStack);
class Demo extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
email: ""
};
}
componentDidMount() {
const email = AsyncStorage.getItem("email").then(email => {
this.setState({
isLoading: false,
email: email
});
});
}
render() {
if (this.state.isLoading) {
return (
<View>
<Text>Loading..</Text>
</View>
);
}
if (this.props.email !== "") {
return <Home />;
} else {
return <AppContainer />;
}
}
}
export default Demo;
AppRegistry.registerComponent("Demo", () => Demo);
Instead of
export default Demo;
Use this :
export default AppContainer;
or
export default createAppContainer(RootStack);

React Navigation 3 - Calling Inside Saga

I am developing an App that uses redux-sagas and react-navigation v3.
The problem that I am facing right now is that I want to use the method navigate inside the saga. The action actually is dispatched, I can see it in the logger, but it doesn't change my screen.
Here are my files:
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Provider } from 'react-redux';
import store from './store';
import Navigator from './routes/index.js'
export default function App() {
return (
<Provider store={store}>
<Navigator />
</Provider>
);
}
routes.js
import React from "react";
import { View, Text } from "react-native";
import {
createBottomTabNavigator,
createSwitchNavigator,
createStackNavigator,
createAppContainer
} from "react-navigation";
import { FontAwesome } from '#expo/vector-icons';
// Screens
import LoginScreen from '../screens/Login.js';
// Routes
import Leads from './leads.js';
import Settings from './settings.js';
const TabsStack = createBottomTabNavigator(
{
Leads: Leads ,
Settings: Settings,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
const iconSize = 28;
let iconName;
if (routeName === 'Leads') {
iconName = 'home'
} else if(routeName === 'Settings'){
iconName = 'cogs'
}
return <FontAwesome name={iconName} size={iconSize} color={tintColor} />
},
}),
tabBarOptions: {
activeTintColor: '#208DFF',
inactiveTintColor: '#cecece',
showLabel: false
},
}
);
const LoginStack = createStackNavigator({
Login: {
screen: LoginScreen,
navigationOptions: ({navigation}) => ({
header: null
})
}
});
const Router = createSwitchNavigator(
{
Login: LoginStack,
Tabs: TabsStack,
},
{
initialRouteName: "Login"
}
);
export default createAppContainer(Router);
store.js
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from "redux-saga";
import { createLogger } from 'redux-logger';
import sagas from '../sagas/';
import reducers from '../reducers/';
const sagaMiddleware = createSagaMiddleware();
const loggerMiddleware = createLogger({collapsed: true});
const store = createStore(
reducers,
applyMiddleware(sagaMiddleware, loggerMiddleware)
);
sagaMiddleware.run(sagas);
export default store;
and finally my sagas
import { takeLatest, call, put } from "redux-saga/effects";
import { NavigationActions } from "react-navigation";
import * as sessionActions from '../actions/sessions';
import * as navigateActions from '../actions/navigation.js';
import { login } from '../api/index.js';
import { AsyncStorage } from 'react-native';
export function* loginRequest({email, password}){
let response = yield call(login, {email, password})
if(!response.error){
saveToken(response.auth_token);
yield put({type: sessionActions.SESSION_LOGIN_REQUEST_SUCCESS, user: response})
}else{
yield put({type: sessionActions.SESSION_LOGIN_REQUEST_FAILURE, error: response.error})
}
}
export function* loginRequestSuccessful(){
console.log("Teste! 2");
yield put(NavigationActions.navigate({ routeName: 'Leads' }))
}
async function saveToken(token) {
try {
return await AsyncStorage.setItem("auth_token", token);
} catch (err) {
console.error(err);
}
}
function* loginSaga(){
yield takeLatest(sessionActions.SESSION_LOGIN_REQUEST, loginRequest);
yield takeLatest(sessionActions.SESSION_LOGIN_REQUEST_SUCCESS, loginRequestSuccessful);
}
export default loginSaga;
I get this from the logger
action Navigation/NAVIGATE # 20:23:07.668
RemoteConsole.js:80 prev state {sessions: {…}}
RemoteConsole.js:80 action {type: "Navigation/NAVIGATE", routeName: "Leads", ##redux-saga/SAGA_ACTION: true}
RemoteConsole.js:80 next state {sessions: {…}}
I don't know how can I navigate to another screen inside a sagas function.
The only way I got navigation working is using this.props.navigation inside the component, but I need to work inside the sagas.
In my project, I do it as follow:
Step 1: Set ref for the AppNavigationContainer like
AppContainer = createAppContainer(this.Switch);
constructor(props: any) {
super(props);
this.state = {};
}
handleNavigationChange = (
prevState: NavigationState,
newState: NavigationState,
action: NavigationAction,
) => {
};
render(): React.ReactNode {
return (
<Root>
{/* <StatusBar barStyle="dark-content" /> */}
<this.AppContainer
ref={(navigatorRef: any) => {
serviceProvider.NavigatorService().setContainer(navigatorRef);
}}
onNavigationStateChange={this.handleNavigationChange}
/>
</Root>
);
}
Step 2: Add the navigation service which is called by the ref in this.AppContainer
import { NavigationActions, NavigationParams, NavigationRoute, NavigationContainerComponent, NavigationContainer } from 'react-navigation';
export default class NavigatorService {
container?: NavigationContainerComponent & NavigationContainer;
setContainer = (container: NavigationContainerComponent & NavigationContainer): void => {
this.container = container;
}
getContainer = (container: NavigationContainerComponent & NavigationContainer): any => {
return container;
}
navigate = (routeName: string, params?: NavigationParams): void => {
if (this.container) {
this.container.dispatch(
NavigationActions.navigate({
routeName,
params,
}),
);
}
}
goBack = (): void => {
if (this.container) {
this.container.dispatch(
NavigationActions.back(),
);
}
}
getCurrentRoute(): NavigationRoute | null {
if (!this.container || !this.container.state.nav) {
return null;
}
return this.container.state.nav.routes[this.container.state.nav.index] || null;
}
}
Step 3: In Saga, you can call this to navigate to the screen you want
serviceProvider.NavigatorService().navigate(//screenName)

How to navigate to another screen from a Redux form with React navigation?

Basically I want that within a props.handleSubmit function you can navigate to another screen.
Here is my code :
import React, { Component } from "react";
import { createStackNavigator, createAppContainer } from 'react-navigation';
import { Provider } from 'react-redux';
import Store from './Store/Store'
import ScreenSignUp from './Navigation/ScreenSignUp';
import ScreenSignIn from './Navigation/ScreenSignIn';
import ScreenHome from "./Navigation/ScreenHome";
class App extends Component {
render() {
return (
<Provider store={Store}>
<AppContainer />
</Provider>
);
}
}
export default App;
const RootStack = createStackNavigator(
{
Home: ScreenHome,
SignUp: ScreenSignUp,
SignIn: ScreenSignIn,
},
{
initialRouteName: 'SignIn',
defaultNavigationOptions: {
header: null,
},
},
);
const AppContainer = createAppContainer(RootStack);
you can do it like this
export default reduxForm({
form: 'SignInForm',
onSubmitSuccess : (result, dispatch, props) => {
props.navigation.navigate('Register');
},
onSubmitFail : () => {
Toast.show({
text: "Enter Passport Number",
duration: 2500,
position: "top",
textStyle: { textAlign: "center" }
});
}
validate,
})(SignInForm);

React Native: Invariant Violation: The navigation prop is missing for this navigator

My code is as follows:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
import {LoginNavigator} from './src/components/login/LoginNavigator'
import {MainNavigator} from './src/components/main/MainNavigator'
import FBSDK from 'react-native-fbsdk'
import {createSwitchNavigator} from 'react-navigation'
const { AccessToken } = FBSDK
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
accessToken: null
}
}
componentDidMount() {
AccessToken.getCurrentAccessToken()
.then((data) => {
this.setState({
accessToken: data.accessToken
})
})
.catch(error => {
console.log(error)
})
}
render() {
const Navigator = makeRootNavigator(this.state.accessToken)
return <Navigator />
}
}
const makeRootNavigator = (isLoggedIn) => {
return createSwitchNavigator(
{
LoginNavigator: {
screen: LoginNavigator
},
MainNavigator: {
screen: MainNavigator
}
},
{
initialRouteName: isLoggedIn ? "MainNavigator" : "LoginNavigator"
}
)
}
and I'm getting the error above. Since my Navigators depend on the variables created in construtor, I needed to do it via render(). Following react-native documentation on application containers didn't help.
In react-navigation v3, you must wrap makeRootNavigator with createAppContainer. Change your code to :
render() {
const Navigator = createAppContainer(makeRootNavigator(this.state.accessToken));
return <Navigator />
}
and don't forget to import createAppContainer on top of the file
import {createSwitchNavigator, createAppContainer} from 'react-navigation'
This is working solution for above problem
import { createStackNavigator } from 'react-navigation-stack'
import Login from './src/Login';
import Fruits from './src/Fruits';
import FruitZoom from './src/FruitZoom';
import {createAppContainer } from 'react-navigation';
import React from 'react';
const AppNavigator = createStackNavigator({
Login: { screen:Login},
Fruits: { screen: Fruits},
FruitZoom: { screen: FruitZoom}
}, {
initialRouteName: 'Login',
headerMode: 'none'
});
const Apps = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return <Apps />;
}
}