I'm trying to use react-native-flash-message to provide little toasts in my app, and I am supposed to add the flash message to my root view. I cannot figure out where that is in my app. I used examples to get up and running with mobx/react-navigation/react-native, and so my app.js actually just exports an index.js that looks like this:
import React from 'react';
import { createRootNavigator } from './router';
import { isSignedIn } from './auth';
import { Font, SplashScreen } from 'expo';
import { library } from '#fortawesome/fontawesome-svg-core';
import { faCheckSquare, faCoffee, faHome } from '#fortawesome/free-solid-svg-icons';
import { configure } from 'mobx';
import { Provider } from 'mobx-react';
import _ from 'lodash';
import { RootStore } from './stores/RootStore';
import { getDecoratedStores } from './stores/util/store-decorator';
import { AsyncStorage } from 'react-native';
import FlashMessage from "react-native-flash-message";
configure({ enforceActions: 'observed' });
const rootStore = new RootStore();
const stores = getDecoratedStores(rootStore);
//Library of Icons
library.add(faCheckSquare, faCoffee, faHome);
export default class App extends React.Component<
{},
{ checkedSignIn: boolean; signedIn: boolean; loaded: boolean }
> {
constructor(props: any) {
super(props);
this.state = {
signedIn: false,
checkedSignIn: false,
loaded: false,
};
}
componentWillMount() {
this._loadFontsAsync();
}
_loadFontsAsync = async () => {
await Font.loadAsync({ robotoBold: require('../app/uiComponents/fonts/Roboto-Bold.ttf') });
await Font.loadAsync({
robotoRegular: require('../app/uiComponents/fonts/Roboto-Regular.ttf'),
});
this.setState({ loaded: true });
};
componentDidMount() {
isSignedIn()
.then(res => {
SplashScreen.hide();
this.setState({ signedIn: res as boolean, checkedSignIn: true });
})
.catch(err => {console.log(err); alert('Error')});
}
render() {
const { checkedSignIn, signedIn } = this.state;
// If we haven't checked AsyncStorage yet, don't render anything (better ways to do this)
if (!checkedSignIn) {
return null;
}
AsyncStorage.getItem('auth-demo-key').then((data) => console.log("Async Storage: " + data));
const Layout = createRootNavigator(signedIn);
return (
<Provider {...stores}>
<Layout />
</Provider>
);
}
}
Can anyone help me figure out how to add my flash message in this return statement? I tried wrapping the provider in a view, but that failed and crashed my app, same with adding it within the provider (a view), also tried just adding flash message here in the provider, but that failed, too. Can anyone help?
Related
I've been battling a bug in my code for the last 4 days and would appreciate some pointers to get me going in the right directions. Component is working fine as long as there is internet connection, but if there is no internet connection, audios and videos are not playing, only thumbnail present.
I'm using netInfo's NetInfo.fetch() to check for connection. If there is connection, I'm refetching data to check for any updates to student assignments.
I'm using expo-av for playing audio/video files (v10.2.1). I'm also using useQuery hook from react-query to fetch data about audio and video files (like url etc.) My video player component is something like this:
Video Player:
import React, {
forwardRef,
ForwardRefRenderFunction,
useCallback,
useImperativeHandle,
useRef
} from 'react';
import { Platform } from 'react-native';
import Orientation from 'react-native-orientation-locker';
import { Audio, Video, VideoFullscreenUpdateEvent, VideoProps } from 'expo-av';
const Player: ForwardRefRenderFunction<
Video | undefined,
VideoProps
> = (props, ref) => {
const innerRef = useRef<Video>(null);
const orientation = useCallback<
(event: VideoFullscreenUpdateEvent) => void
>(
(event) => {
if (Platform.OS === 'android') {
if (
event.fullscreenUpdate === Video.FULLSCREEN_UPDATE_PLAYER_DID_PRESENT
) {
Orientation.unlockAllOrientations();
} else if (
event.fullscreenUpdate === Video.FULLSCREEN_UPDATE_PLAYER_DID_DISMISS
) {
Orientation.lockToPortrait();
}
}
props.onFullscreenUpdate?.(event);
},
[props]
);
useImperativeHandle(ref, () => {
if (innerRef.current) {
return innerRef.current;
}
return undefined;
});
return (
<Video
resizeMode="contain"
useNativeControls
ref={innerRef}
onLoad={loading}
{...props}
onFullscreenUpdate={orientation}
/>
);
};
export const VideoPlayer = forwardRef(Player);
Custom Hook:
For async state management, I'm using a custom react-query hook, that looks something like this (non-relevant imports and code removed):
import { useFocusEffect } from '#react-navigation/core';
import { useCallback } from 'react';
import NetInfo from '#react-native-community/netinfo';
export const useStudentAssignment = (
assignmentId: Assignment['id']
): UseQueryResult<Assignment, Error> => {
const listKey = studentAssignmentKeys.list({ assignedToIdEq: studentData?.id });
const queryClient = useQueryClient();
const data = useQuery<Assignment, Error>(
studentAssignmentKeys.detail(assignmentId),
async () => {
const { data: assignment } = await SystemAPI.fetchAssignment(assignmentId);
return Assignment.deserialize({
...assignment,
});
},
{
staleTime: 1000 * 60 * 30,
initialData: () => {
const cache= queryClient.getQueryData<Assignment[]>(listKey);
return cache?.find((assignment) => assignment.id === assignmentId);
},
initialDataUpdatedAt: queryClient.getQueryState(listKey)?.dataUpdatedAt,
}
);
useFocusEffect(
useCallback(() => {
NetInfo.fetch().then((state) => {
if (state.isConnected) {
data.refetch();
}
});
}, [data])
);
return data;
};
Component:
import React, { FC, useCallback, useEffect, useMemo, useRef } from 'react';
import { SafeAreaView } from 'react-native-safe-area-context';
import { StackScreenProps } from '#react-navigation/stack';
import { ROUTES } from 'enums/SMSRoutes';
import { StoreType } from 'enums/SMSStoreType';
import { useStudentAssignment } from 'hooks/Assignments/useStudentAssignment';
import { RootStackParamList } from 'navigators';
import { AssignmentViewer } from 'screens/AssignmentViewer';
type NavProps = StackScreenProps<
RootStackParamList,
ROUTES.ASSIGNMENT_VIEW
>;
export const AssignmentView: FC<NavProps> = ({
navigation,
route: {
params: { assignmentId }
}
}) => {
const assignmentQuery = useStudentAssignment(assignmentId);
const assignmentTracker = useStore(StoreType.AssignmentTracker);
const isDoneRef = useRef<boolean>(false);
const questions = assignmentQuery.data?.questions || [];
const activeQuestion = useMemo(() => {
return questions.filter((question) => question.active);
}, [questions]);
const onDone = useCallback(() => {
isDoneRef.current = true;
navigation.push(ROUTES.ASSIGNMENT_COMPLETED);
}, [navigation]);
useEffect(() => {
assignmentTracker.start(assignmentId);
return () => {
assignmentTracker.finish(isDoneRef.current);
};
}, []);
return (
<SafeAreaView>
<AssignmentViewer
questions={activeQuestion}
onDone={onDone}
isLoading={assignmentQuery.isLoading}
/>
</SafeAreaView>
);
};
What I'm trying to do here is that if internet connection is connected and the user navigates to the current view (which is used to view assignments), I'd like to refetch the data. Per the requirements, I can't use the staleTime property or any other interval based refetching.
Component is working fine if I don't refetch, or if internet connection is present. If connection isn't there, it doesn't play the cache'd audio/video.
If I take out the check for internet connection (remove netInfo), component display videos both offline and online. However, refetching fails due to no connectivity.
What should I change to make sure that data is refetched when connected and videos are played even if not connected to Internet?
When I try to enter username and then go on next screen for live chating then I facing this error.
Here is code for ChatScreen.js file.
TypeError: undefined is not a function (near '..._fire.default.get...').
ChatScreen.js
import React,{Component} from "react";
import {Platform,KeyboardAvoidingView} from 'react-native';
import {GiftedChat}from 'react-native-gifted-chat-fix';
import{SafeAreaView}from 'react-native-safe-area-view';
import Video from 'react-native-video';
import Fire from '../fire';
export default class ChatScreen extends Component{
state={
messages:[]
}
get user(){
return{
_id:Fire.uid,
name:this.props.navigation.state.params.name
}
}
componentDidMount(){
Fire.get(message=>this.setState(previous=>({
messages:GiftedChat.append(previous.messages,message)
}))
);
}
componentWillUnmount(){
Fire.off()
}
render(){
const chat=<GiftedChat messages={this.state.messages} onSend={Fire.send} user={this.user}/>;
if(Platform.OS=='android'){
return(
<KeyboardAvoidingView style={{flex:1}}behavior="padding" keyboardVerticalOffset={30} enabled>
{chat}
</KeyboardAvoidingView>
);
}
return<SafeAreaView style={{flex:1}}>{chat}</SafeAreaView>;
}
}
Try changing the code in both files
At first in Fire.js
import firebase from 'firebase'; // 4.8.1
class Fire {
constructor() {
this.init();
this.observeAuth();
}
init = () => {
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey:'AIzaSyAPfes9_2EwZESX1puYMUv29yunzK9Ve5U',
authDomain:'docman-31d96.firebaseapp.com',
databaseURL: "https://docman-31d96.firebaseio.com",
projectId: "docman-31d96",
storageBucket: "docman-31d96.appspot.com",
messagingSenderId: "649332068608",
appId:'1:649332068608:android:08c080ee6a4e521f5323e5'
});
}
};
observeAuth = () =>
firebase.auth().onAuthStateChanged(this.onAuthStateChanged);
onAuthStateChanged = user => {
if (!user) {
try {
firebase.auth().signInAnonymously();
} catch ({ message }) {
alert(message);
}
}
};
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get ref() {
return firebase.database().ref('messages');
}
parse = snapshot => {
const { timestamp: numberStamp, text, user } = snapshot.val();
const { key: _id } = snapshot;
const timestamp = new Date(numberStamp);
const message = {
_id,
timestamp,
text,
user,
};
return message;
};
on = callback =>
this.ref
.limitToLast(20)
.on('child_added', snapshot => callback(this.parse(snapshot)));
get timestamp() {
return firebase.database.ServerValue.TIMESTAMP;
}
// send the message to the Backend
send = messages => {
for (let i = 0; i < messages.length; i++) {
const { text, user } = messages[i];
const message = {
text,
user,
timestamp: this.timestamp,
};
this.append(message);
}
};
append = message => this.ref.push(message);
// close the connection to the Backend
off() {
this.ref.off();
}
}
Fire.shared = new Fire();
export default Fire;
and then in ChatScreen.js
import * as React from 'react';
import { Platform , KeyboardAvoidingView,SafeAreaView } from 'react-native';
// #flow
import { GiftedChat } from 'react-native-gifted-chat'; // 0.3.0
import Fire from '../fire';
type Props = {
name?: string,
};
class ChatScreen extends React.Component<Props> {
static navigationOptions = ({ navigation }) => ({
title: (navigation.state.params || {}).name || 'Chat!',
});
state = {
messages: [],
};
get user() {
return {
name: this.props.navigation.state.params.name,
_id: Fire.shared.uid,
};
}
render() {
const chat=<GiftedChat messages={this.state.messages} onSend={Fire.shared.send} user={this.user}/>;
if(Platform.OS=='android'){
return(
<KeyboardAvoidingView style={{flex:1}}behavior="padding" keyboardVerticalOffset={0} enabled>
{chat}
</KeyboardAvoidingView>
);
}
return<SafeAreaView style={{flex:1}}>{chat}</SafeAreaView>;
}
componentDidMount() {
Fire.shared.on(message =>
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, message),
}))
);
}
componentWillUnmount() {
Fire.shared.off();
}
}
export default ChatScreen;
This helped for me It should work for you too
To see my chat app just visit https://snack.expo.io/#habibishaikh1/chatapp
I am trying to create a React Native App thats trying to fetch the current location using the navigator.geolocation.getCurrentPosition function and i encounter the error 'Cannot read property 'getCurrentPosition' of undefined'
The following is the code that i use:
import update from "react-addons-update";
import constants from "./actionConstants";
//----------------------
//Constants
//----------------------
const { GET_CURRENT_LOCATION } = constants;
//----------------------
// Actions
//----------------------
export function getCurrentLocation(){
return(dispatch)=>{
navigator.geolocation.getCurrentPosition(
(position)=>{
dispatch({
type:GET_CURRENT_LOCATION,
payload:position
});
},
(error)=> console.log(error.message),
{enableHighAccuracy: true, timeout: 20000, maximumAge:1000}
);
}
}
//----------------------
// Action Handlers
//----------------------
function handleGetCurrentLocation(state, action){
return update(state,{
region:{
$set:action.payload
}
})
}
const ACTION_HANDLERS = {
GET_CURRENT_LOCATION:handleGetCurrentLocation
}
const initialState = {
region: {}
};
export function HomeReducer(state = initialState, action){
const handler = ACTION_HANDLERS[action.type];
return handler ? handler(state, action) : state;
}
My actionConstants.js file is:
export default {
GET_CURRENT_LOCATION:"GET_CURRENT_LOCATION"
};
This is being called in the following file :
import React from "react";
import {View, Text} from "react-native";
import MapContainer from "./MapContainer";
import {Container} from "native-base";
export default class Home extends React.Component{
componentDidMount(){
this.props.getCurrentLocation();
}
render(){
const region = {
latitude : 3.146642,
longitude : 101.695845,
latitudeDelta:0.0922,
longitudeDelta:0.0421
}
return(
<Container>
<MapContainer region={region}/>
</Container>
);
}
}
Could someone help.. Thanks in advance!!!
what is navigator ?
here is my working code
import Geolocation from 'react-native-geolocation-service';
componentWillMount() {
Geolocation.getCurrentPosition(
(position) => {
addLocation(position.coords);
},
(error) => {
console.error(error);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
);
}
where have you called getCurrentLocation? it seems you have not called it.
For me, this code works without importing any extra library:
import React, { Component } from 'react';
import {ToastAndroid } from 'react-native';
export default class location extends Component {
constructor(props) {
super(props);
this.state = {
};
}
getCurrentLocation(){
navigator.geolocation.getCurrentPosition((position) => {
ToastAndroid.show((position.coords.latitude + ', ' + position.coords.longitude),ToastAndroid.LONG);
}, function (e) {
ToastAndroid.show(e, ToastAndroid.SHORT)
}, {enableHighAccuracy: true, timeout: 20000, maximumAge:1000});
}
render() {
return (
<View>{this.getCurrentLocation()}</View>
);
}
}
index.js
import React from 'react';
import {
AppRegistry
} from 'react-native'
import App from './App';
import { YellowBox } from 'react-native';
YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated', 'Module RCTImageLoader']);
AppRegistry.registerComponent('mhagora', () => App);
App.js
import React, { Component } from 'react';
import { Provider } from "react-redux";
import store from './app/store';
import { StyleProvider, getTheme } from "native-base";
import Setup from "./app/setup";
import variables from "./app/theme/variables/commonColor";
export default class App extends Component {
render() {
return (
<Provider store={store}>
<StyleProvider style={getTheme(variables)}>
<Setup />
</StyleProvider>
</Provider>
);
}
}
./app/setup.js
import React, { Component } from "react";
import axios from "axios/index";
import Config from "./config";
import { Root } from "native-base";
import AppNavigator from "./routes";
axios.defaults.baseURL = Config.API_BASE_URL;
axios.defaults.headers.common['Content-Type'] = Config.API_ACCEPT;
axios.defaults.headers.common['Accept'] = Config.API_ACCEPT;
axios.defaults.headers.common['secret'] = Config.API_SECRET;
export default class Setup extends Component {
render() {
return (
<Root>
<AppNavigator />
</Root>
);
}
}
./app/store/index.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';
import reducers from '../reducers';
const logger = createLogger();
export default createStore(reducers, compose(applyMiddleware(thunk, logger)));
./app/actions/index.js
import { APP_LOADING, APP_LOADED } from '../actionTypes';
export function appLoading() {
return (dispatch) => {
dispatch({type: APP_LOADING});
}
}
export function appLoaded() {
return (dispatch) => {
dispatch({type: APP_LOADED});
}
}
./app/actions/user.js
import { USER_LOADING, USER_LOADED, USER_FAILED, APP_LOADING, APP_LOADED } from "../actionTypes";
import axios from 'axios';
import Config from '../config';
export function userLogin(username, password) {
return (dispatch) => {
dispatch({type: USER_LOADING});
axios
.post("oauth/token", {
username: username,
password: password,
client_id: Config.API_CLIENT_ID,
client_secret: Config.API_CLIENT_SECRET,
grant_type: 'password',
}, {
headers: {}
})
.then(response => {
dispatch({
type: USER_LOADED,
data: response.data
});
})
.catch(err => {
dispatch({ type: USER_FAILED, error: err.response.data.message });
alert(err.response.data.message);
});
};
}
./app/reducers/index.js
import appReducer from './appReducer';
import userReducer from './userReducer';
import { combineReducers } from "redux";
const rootReducer = combineReducers({
appReducer,
userReducer
});
export default rootReducer;
./app/reducers/userReducer.js
import { USER_LOADING, USER_LOADED, USER_FAILED } from '../actionTypes';
const initialState = {
username: "",
password: "",
user: {}
};
export default userReducer = (state = initialState, action) => {
switch (action.type) {
case USER_LOADING:
return Object.assign({}, state, {
loading: true,
user: {},
});
case USER_LOADED:
return Object.assign({}, state, {
loading: false,
user: action.data
});
case USER_FAILED:
return Object.assign({}, state, {
loading: false,
});
default:
return state
}
}
./app/reducers/appReducer.js
import { APP_LOADING, APP_LOADED } from "../actionTypes";
const initialState = {
loading: true,
};
export default appReducer = (state = initialState, action) => {
switch (action.type) {
case APP_LOADING:
return Object.assign({}, state, {
loading: true
});
case APP_LOADED:
return Object.assign({}, state, {
loading: false
});
default:
return state;
}
};
./app/screens/home.js
'use strict';
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { SkypeIndicator } from 'react-native-indicators';
import * as Actions from '../actions/index';
import { Container, Header, Title, Content, Footer, FooterTab, Button, Left, Right, Body, Icon, Text, View } from 'native-base';
class HomeScreen extends Component {
componentDidMount() {
/** HERE, the apps should show a loading page forever but it didn't **/
// setTimeout( _ => {
// this.props.appLoaded();
// }, 2000);
}
render() {
if (this.props.loading) {
return (
<SkypeIndicator />
);
} else {
return (
<Container>
<Header>
</Header>
<Body>
<Button
onPress={() =>
this.props.navigation.navigate('LoginScreen')
}><Text>Login now</Text></Button>
<Text>Hello</Text>
</Body>
</Container>
);
}
}
}
// The function takes data from the app current state,
// and insert/links it into the props of our component.
// This function makes Redux know that this component needs to be passed a piece of the state
function mapStateToProps(state, props) {
return {
loading: state.loading,
user: state.user,
}
}
// Doing this merges our actions into the component’s props,
// while wrapping them in dispatch() so that they immediately dispatch an Action.
// Just by doing this, we will have access to the actions defined in out actions file (action/homeScreen.js)
function mapDispatchToProps(dispatch) {
return bindActionCreators(Actions, dispatch);
}
//Connect everything
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);
./app/screens/loginScreen
'use strict';
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { SkypeIndicator } from 'react-native-indicators';
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { Body, Button, Container, Content, Header, Icon, Left, Text, Title, View } from "native-base";
import t from 'tcomb-form-native';
import { LoginUserModel, LoginUserModelOption } from "../models/UserModel";
import styles from '../styles';
import LoadingButton from 'react-native-loading-button';
import * as UserActions from '../actions/user';
const Form = t.form.Form;
const ps = StyleSheet.create({
...styles,
container: {
justifyContent: 'center',
marginTop: 50,
padding: 20
},
});
class LoginScreen extends Component {
constructor(props) {
super(props);
}
onSubmitHandler = () => {
const value = this._form.getValue();
if(value) {
this.props.userLogin(value.username, value.password);
}
};
render() {
return (
<Container>
<Header>
<Left>
<Button transparent onPress={() => this.props.navigation.goBack()}>
<Icon name="arrow-back"/>
</Button>
</Left>
<Body>
<Title>Headers</Title>
</Body>
</Header>
<Content padder>
<View style={ps.container}>
<Form ref={c => this._form = c} type={LoginUserModel} options={LoginUserModelOption} />
<LoadingButton
block
onPress={this.onSubmitHandler.bind(this)}
isLoading={this.props.loading}
style={{ justifyContent: 'center' }}
><Icon name="checkmark"/><Text>Login Now</Text></LoadingButton>
</View>
</Content>
</Container>
);
}
}
// The function takes data from the app current state,
// and insert/links it into the props of our component.
// This function makes Redux know that this component needs to be passed a piece of the state
function mapStateToProps(state, props) {
return {
loading: state.loading,
user: state.user,
}
}
// Doing this merges our actions into the component’s props,
// while wrapping them in dispatch() so that they immediately dispatch an Action.
// Just by doing this, we will have access to the actions defined in out actions file (action/homeScreen.js)
function mapDispatchToProps(dispatch) {
return bindActionCreators(UserActions, dispatch);
}
//Connect everything
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
the homeScreen should result in a forever loading page but it didn't
the loginScreen button should automatically loading when pressing, but it didn't
new to react-native, i have tried to set/play with the state/props but it just seems like not changing/connected, i also have another page trying to check the state is synced but results is like always get the fresh state, as my understanding the state is something like GLOBAL variable accessible in any component connect to redux
MY QUESTION IS
1. is the react-native/redux/redux-thunk setup correctly? if not, where is the error
2. is the state/props is global accessible in any component that connect with redux
3. if statement 2 is correct, what the different between state/props? this.state and this.props
4. i don't really understand the promise work, how can we handle / wait untill the api call complete(success/error) before move to next step/flow, i use php a lot and my logic is stuck at each function should return something then depends on the results process to next function...and then...
your answer / precious time spend for reading this question is appreciated, thank you
created a github for easy to reproduce/test
https://github.com/weiloon1234/react-native-test
I'm trying to get data from App.js for network connection availability. I'm getting data from App.js to action and reducer but the reducer is not updating the state for my component. The console log in the reducer is working but I'm not able to get data in the mapStateToProps of myComponent.
My App.js file contains this code.
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { NetInfo } from 'react-native';
import { createStore, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import reducers from './src/reducers';
import Router from './src/Router';
import { internetConnectionChanged } from './src/actions/';
class App extends Component {
componentWillMount() {
NetInfo.isConnected.addEventListener('connectionChange', this.handleConnectionChange);
}
componentWillUnmount() {
NetInfo.isConnected.removeEventListener('connectionChange', this.handleConnectionChange);
}
handleConnectionChange = (isConnected) => {
NetInfo.isConnected.fetch().done(
(isConnecteds) => {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
store.dispatch(internetConnectionChanged(isConnecteds));
});
};
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<Router />
</Provider>
);
}
}
export default App;
My code in action file is
import { CONNECTION_CHANGE } from '../actions/types';
export const internetConnectionChanged = (isConnected) => {
return {
type: CONNECTION_CHANGE,
payload: isConnected
};
};
That is exported via the index.js of actions file
through export * from './AppActions';
Code for the reducer is
import { CONNECTION_CHANGE } from '../actions/types';
const INITIAL_STATE = { isConnected: false };
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case CONNECTION_CHANGE:
console.log(action.payload);
return { ...state, isConnected: action.payload };
default:
return state;
}
};
Under my component, this is the code to get the info is
const mapStateToProps = ({ auth, app }) => {
const { email, password, error, loading } = auth;
const { isConnected } = app;
return { email, password, error, loading, isConnected };
};
export default connect(mapStateToProps, {
emailChanged,
passwordChanged,
loginUser,
forgotPasswordAction,
})(LoginForm);
Create store outside the App class. This might be causing the store to always have initial reducer values. Just paste the below line before Class App extends Component line
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
Also remove the same above line of code from the following function
handleConnectionChange = (isConnected) => {
NetInfo.isConnected.fetch().done(
(isConnecteds) => {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk)); //remove this line
store.dispatch(internetConnectionChanged(isConnecteds));
});
};