react-native navigationV3 integrating redux - react-native

My objective is to implement redux into my react-native proj. But it's not an error, it's unsuccessful. How can I organize my code such that it'll work?
App.js
import React from 'react';
import { AppRegistry } from 'react-native';
import { Provider } from 'react-redux';
import ReduxNavigation from './src/navigation/ReduxNavigation';
import AppReducer from './src/reducers/index';
import { middleware } from './src/utils/redux';
import { createStore, applyMiddleware } from 'redux';
import { logger } from 'redux-logger';
import thunk from 'redux-thunk';
import AppNavigation from './src/navigation/AppNavigation';
//import promise from 'redux-promise-middleware';
import { NavigationActions } from 'react-navigation';
// create our store
const store = createStore(AppReducer, applyMiddleware(thunk, logger));
class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppNavigation />
</Provider>
);
}
}
export default App;
../utils/redux
import {
createReactNavigationReduxMiddleware,
reduxifyNavigator,
createNavigationReducer,
} from 'react-navigation-redux-helpers';
import { createStackNavigator } from 'react-navigation';
const middleware = createReactNavigationReduxMiddleware(
'root',
state => state.nav
);
const App = reduxifyNavigator('root');
export { middleware, App };
../navigation/navReducer
import { NavigationActions } from 'react-navigation';
import AppNavigation from '../navigation/AppNavigation';
const firstAction = AppNavigation.router.getActionForPathAndParams(
'initialStack'
);
const tempNavState = AppNavigation.router.getStateForAction(firstAction);
const initialNavState = AppNavigation.router.getStateForAction(tempNavState);
const nav = (state = initialNavState, action) => {
let nextState;
switch (action.type) {
default: {
nextState = AppNavigation.router.getStateForAction(action, state);
break;
}
}
return nextState || state;
};
export default nav;
../reducers/index
import { combineReducers } from 'redux';
import transactionsReducer from './transactionsReducer';
import setVisibilityFilter from './setVisibilityFilter';
import userReducer from './userReducer';
import AppNavigation from '../navigation/AppNavigation';
import { createNavigationReducer } from 'react-navigation-redux-helpers';
import nav from './navReducer';
const navReducer = createNavigationReducer(AppNavigation);
const AppReducer = combineReducers({
nav: navReducer,
transactionsReducer,
setVisibilityFilter,
userReducer,
});
export default AppReducer;
../navigation/ReduxNavigation
import React from 'react';
import { addNavigationHelpers,StackNavigator } from 'react-navigation';
import { connect } from 'react-redux';
import {AppNavigation} from './AppNavigation';
class ReduxNavigation extends React.Component {
render() {
const { dispatch, nav } = this.props;
return (
<AppNavigation
navigation={addNavigationHelpers({
dispatch,
state: nav,
})}
/>
);
}
}
const mapStateToProps = state => ({
nav: state.nav,
});
export default connect(mapStateToProps)(ReduxNavigation);
../navigation/AppNavigation
//please consider all my screens to be dumb for transparency..
import React from 'react';
import { StackNavigator, createDrawerNavigator } from 'react-navigation';
import { Button, Icon } from 'native-base';
import InitialScreen from '../containers/InitialScreen';
//import ForgottenPasswordScreen from '../containers/ForgottenPassword';
import Transactions from '../containers/Transactions';
import Screen1 from '../containers/Screen1';
import Screen2 from '../containers/Screen2';
import Screen3 from '../containers/Screen3';
import SignIn from '../containers/SignIn';
import Accounts from '../components/Accounts';
import SignUp from '../containers/SignUp';
// drawer stack
const DrawerStack = createDrawerNavigator({
screen1: { screen: Screen1 },
screen2: { screen: Screen2 },
screen3: { screen: Screen3 },
});
const DrawerNavigation = StackNavigator(
{
DrawerStack: { screen: DrawerStack },
},
{
headerMode: 'float',
}
);
// login stack
const LoginStack = StackNavigator({
transactionsScreen: { screen: Transactions },
});
const initialStack = StackNavigator({
initialScreen: { screen: InitialScreen },
});
// Manifest of possible screens
export const AppNavigation = StackNavigator(
{
initialStack: { screen: initialStack },
drawerStack: { screen: DrawerNavigation },
loginStack: { screen: LoginStack },
},
{
headerMode: 'none',
title: 'Main',
initialRouteName: 'initialStack',
}
);
I'm a beginner and it's highly likely my code structures could be wrong, but this is the basic idea. I have to use navigationV3.
Would someone go through this and advise me on my bad practices on the above code? I want to improve my coding style.
Would someone also create and share a boilerplate for the above scenario? EXPO compactable.

Related

TypeError: cannot read property 'routes' of undefined

I'm using React-navigation 4 with redux and redux-helpers methods. We are trying to navigate through pages using NavigationAction, please find some of the details below:-
We have three steps process to login
validate contact no and then further process with password/OTP
To implement this functionality i have to dispatch and NavigationAction on the basis of some condition. But stucked in between routing.
here is my ConfigureStore.js
import { createStore, combineReducers, compose, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import logger from 'redux-logger'
import uiReducer from "./reducers/ui";
// import navReducer from "./reducers/nav";
import authReducer from "./reducers/Auth";
import {
createReactNavigationReduxMiddleware,
createNavigationReducer,
} from 'react-navigation-redux-helpers';
import Navigator from '../router/router';
const navReducer = createNavigationReducer(Navigator);
const rootReducer = combineReducers({
ui: uiReducer,
nav: navReducer,
auth : authReducer
});
const navMiddleWare = createReactNavigationReduxMiddleware(
state => state.nav,
);
const configureStore = () => {
return createStore(rootReducer, applyMiddleware(thunk, logger, navMiddleWare));
};
export default configureStore;
Here is the Routes.js
import {
createAppContainer,
createSwitchNavigator
} from "react-navigation";
import { createStackNavigator } from 'react-navigation-stack';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import LoginAuthScreen from './../screens/Auth/Login/Login';
import HomeScreen from './../screens/Home/Home';
import WorkoutScreen from './../screens/Workout/WorkoutScreen';
import HistoryScreen from './../screens/History/HistoryScreen';
import StudioScreen from './../screens/Studios/StudioScreen';
import footerComponent from './../component/Footer/Footer';
import AuthLoadingScreen from './../screens/Auth/AuthLoader';
import Step1 from './../screens/Auth/Login/Step1';
import Step2 from './../screens/Auth/Login/Step2';
AuthStack = createStackNavigator({
Login: {
screen: LoginAuthScreen,
navigationOptions: {
header: null,
}
},
LoginStep1: {
screen: Step1,
navigationOptions: {
header: null,
}
},
LoginStep2: {
screen: Step2,
navigationOptions: {
header: null,
}
}
})
TabNavigator = createBottomTabNavigator({
Home: HomeScreen,
Workout: WorkoutScreen,
Studio: StudioScreen,
History : HistoryScreen
}, {
tabBarComponent: footerComponent,
});
export default AppRouterConfig = createAppContainer(createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: TabNavigator,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
));
Index.js
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import configureStore from './src/app/store/configureStore';
import { Provider, connect } from 'react-redux';
import { createReduxContainer } from 'react-navigation-redux-helpers';
import { Root } from 'native-base';
import Navigator from './src/app/router/router';
const store = configureStore();
const App = createReduxContainer(Navigator);
const mapStateToProps = (state) => ({
nav: state.nav,
});
const mergeProps = (state, dispatch, ownProps) => {
return ({
...ownProps,
screenProps: {
...ownProps.screenProps,
...state,
...dispatch,
}
})
}
const AppWithNavigationState = connect(mapStateToProps, null, mergeProps)(App);
class Main extends Component {
render() {
return (
<Provider store={store}>
<Root>
<AppWithNavigationState />
</Root>
</Provider>
);
}
}
AppRegistry.registerComponent(appName, () => Main);

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 />;
}
}

how to use Redux with createSwitchNavigator?

I am trying to use switch navigator with redux. following is my code.
import { createSwitchNavigator, createStackNavigator } from 'react-navigation';
import LoginScreen from '../screens/LoginScreen';
import EmployeeListScreen from '../screens/EmployeeListScreen';
import DetailsView from '../screens/EmployeeDetailViewScreen';
import EmployeeForm from '../screens/EmployeeForm';
import AuthLoadingScreen from "../screens/AuthLoadingScreen.js";
import {connect } from "react-redux";
import { AppNavigator } from "../navigations/AppNavigator.js";
const AppStack = createStackNavigator({
List:{screen:EmployeeListScreen},
Detail:{screen:DetailsView},
Form:{screen:EmployeeForm}
});
const AuthStack = createStackNavigator({ Login: LoginScreen });
export const AuthNavigator = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppNavigator,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
);
const AuthWithNavigationState = ({ dispatch, nav }) => (
<AuthNavigator />
);
const mapStateToProps = state => ({
nav: state.nav,
});
export default connect(mapStateToProps)(AuthWithNavigationState);
I'm importing this component is my App.js file and using it as follows to connect with redux store but it is giving me error like, React is not defined and error is located at connect(AuthWithNavigationState)
import React from 'react';
import { Provider } from 'react-redux';
import { createStore,applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import AppReducer from './src/reducers/AppReducer';
import AuthWithNavigationState from './src/navigations/AuthNavigator.js';
const store = createStore(AppReducer,applyMiddleware(thunk));
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<AuthWithNavigationState/>
</Provider>
);
}
}
I've tried to follow instruction from below link but still I am getting the same error.
how can i integrate redux store to react native?
Can anyone tell me what is wrong with my code?
after too much trying, I figure out that, The switch navigator don't need to be connect to the store, so below step was incorrect.
const AuthWithNavigationState = ({ dispatch, nav }) => (
<AuthNavigator />
);
const mapStateToProps = state => ({
nav: state.nav,
});
export default connect(mapStateToProps)(AuthWithNavigationState);
I simply exported AuthNavigator and imported in App.js and this worked for me.
import React from 'react';
import { Provider } from 'react-redux';
import { createStore,applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import AppReducer from './src/reducers/AppReducer';
import AuthNavigatorfrom './src/navigations/AuthNavigator.js';
const store = createStore(AppReducer,applyMiddleware(thunk));
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<AuthNavigator/>
</Provider>
);
}
}

React native initalRouteName not working with Stack Navigation

I am new to react-native and I am trying to implement a simple application using StackNavigation and react-redux with welcome and signup screens. I have configured both the screens using StackNavigation but for some reasons , only the SignUp screen pops up when the app starts. Below are my files :
Index.js
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('MyApp', () => App);
App.js
import React, { Component } from 'react';
import { Provider, connect } from "react-redux";
import { addNavigationHelpers } from "react-navigation";
import StackNavConfig from "./js/config/routes";
import getStore from "./js/store";
const AppNavigator = StackNavConfig;
const initialState = AppNavigator.router.getActionForPathAndParams('Welcome');
const navReducer = (state = initialState, action) => {
const newState = AppNavigator.router.getStateForAction(action, state);
return newState || state;
};
const AppWithNavigationState = connect(state => ({
nav: state.nav,
}))(({ dispatch, nav }) => (
<AppNavigator navigation={addNavigationHelpers({ dispatch, state: nav })} />
));
const store = getStore(navReducer);
class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
}
export default App;
js/config/routes.js
import Welcome from "../components/Welcome/view/Welcome";
import SignUp from "../components/SignUp/view/SignUp";
import { StackNavigator } from "react-navigation";
const Routes = {
Welcome: { screen: Welcome , path: ''},
SignUp: { screen: SignUp , path : '/signup'},
};
const RoutesConfig = {
initialRouteName: 'Welcome',
headerMode: 'none',
};
export default StackNavConfig = StackNavigator(Routes, RoutesConfig);
store.js
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import getRootReducer from "./reducers/index";
export default function getStore(navReducer) {
const store = createStore(
getRootReducer(navReducer),
undefined,
applyMiddleware(thunk)
);
return store;
}
Below are my components
Welcome.js
import React from 'react';
import {
View,
Image} from 'react-native';
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as welcomeActions from "../actions/WelcomeActions";
import { welcomeStyles } from '../styles/WelcomeStyles';
class Welcome extends React.Component {
constructor(){
super();
this.state = { };
}
render(){
return (
<View style = {welcomeStyles.mainContainer}>
<Text>Welcome</Text>
</View>
);
}
}
export default connect(
state => ({
}),
dispatch => bindActionCreators(welcomeActions, dispatch)
)(Welcome);
SignUp.js
import React from 'react';
import {
View,
Image} from 'react-native';
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as welcomeActions from "../actions/SignUpActions";
import { signUpStyles } from '../styles/SignUpStyles';
class Welcome extends React.Component {
constructor(){
super();
this.state = { };
}
render(){
return (
<View style = {signUpStyles.mainContainer}>
<Text>SignUp</Text>
</View>
);
}
}
export default connect(
state => ({
}),
dispatch => bindActionCreators(signUpActions, dispatch)
)(SignUp);
I also have action and reducer files for each of my component.But they are blank as of now , since I haven't yet implemented the redux part.I am combining the reducers as below.
import { combineReducers } from "redux";
import welcomeReducer from "../components/Welcome/reducers/WelcomeReducer";
import signUpReducer from "../components/SignUp/reducers/SignUpReducer";
export default function getRootReducer(navReducer) {
return combineReducers({
nav: navReducer,
welcomeReducer : welcomeReducer,
signUpReducer : signUpReducer,
});
}
As mentioned before , even after setting the initialRouteName to Welcome in my routes.js , the SignUp screen appears first everytime I launch the app. Please help
I found out what was the issue. I was calling this.props.navigate inside the render function by mistake which was causing the navigation to different screen.

Nested Tab bar inside Stack Navigator using react navigation and redux

I have followed this great tutorial which is Tab Bar with three tabs using redux. Everything works great. Now I am trying to nest this Tab Bar inside Stack Navigator but I have the following error:
I am new to Redux and really cannot find where is the problem. Here is my code:
StackNav.js
import React from 'react';
import { connect } from 'react-redux';
import { addNavigationHelpers } from 'react-navigation';
import { RootNav } from './../navigationConfiguration';
const mapStateToProps = (state) => {
return { navigationState: state.nav };
};
class StackNav extends React.Component {
render() {
const { dispatch, navigationState } = this.props;
return (
<RootNav
navigation={
addNavigationHelpers({
dispatch,
state: navigationState,
})
}
/>
);
}
}
export default connect(mapStateToProps)(StackNav);
StackNav's navigationConfiguration.js
import { StackNavigator } from 'react-navigation';
import TabBarNavigation from './../tabBar/views/TabBarNavigation';
import Welcome from './../../Screens/Register/Welcome.js';
const routeConfiguration = {
Welcome: { screen: Welcome },
Home: { screen: TabBarNavigation },
};
const stackNavigatorConfiguration = {
initialRouteName: 'Welcome',
headerMode: 'screen',
navigationOptions: {
header: { visible: false }
}
};
export const RootNav = StackNavigator(routeConfiguration, stackNavigatorConfiguration);
Reducers
import { combineReducers } from 'redux';
// Navigation
import { AppNavigator } from './../stackNav/navigationConfiguration';
import { NavigatorTabOne } from './../tabOne/navigationConfiguration';
import { NavigatorTabTwo } from './../tabTwo/navigationConfiguration';
import { NavigatorTabThree } from './../tabThree/navigationConfiguration';
export default combineReducers({
nav: (state, action) => AppNavigator.router.getStateForAction(action, state),
tabOne: (state, action) => NavigatorTabOne.router.getStateForAction(action, state),
tabTwo: (state, action) => NavigatorTabTwo.router.getStateForAction(action, state),
tabThree: (state, action) => NavigatorTabThree.router.getStateForAction(action, state),
});
I also tried with this reducer instead nav: above
import { AppNavigator } from './../stackNav/navigationConfiguration';
const initialState = AppNavigator.router.getStateForAction(AppNavigator.router.getActionForPathAndParams('Welcome'));
export const navReducer = (state = initialState, action) => {
const nextState = AppNavigator.router.getStateForAction(action, state);
return nextState || state;
};
Start point of the app:
import React from 'react';
import {
AppRegistry,
Text
} from 'react-native';
import { Provider } from 'react-redux';
import StackNav from './../App/stackNav/views/StackNav';
import store from './store';
Text.defaultProps.allowFontScaling = false;
class App extends React.Component {
render() {
return (
<Provider store={store}>
<StackNav />
</Provider>
);
}
}
AppRegistry.registerComponent('MyApp', () => App);
I will appreciate any help. Thank you in advanced!
well, you're importing AppNavigator when you shoould be importing { RootNav } in reducer index
I don't have a direct answer to your question, but I can offer an example of how to nest Tab Navigators in Stack Navigators in this tutorial - https://developerlife.com/2017/04/15/navigation-and-styling-with-react-native/
Here's the JS class (from the tutorial and it's GitHub repo) that sets up the navigators and nesting - https://github.com/r3bl-alliance/react-native-weather/blob/master/app/Router.js