Can't navigate to a nested DrawerNavigator route in react-navigation - javascript

I am trying out react navigation, but I seem to be having trouble with navigating to a nested DrawerNavigator route within my react native app.
After a successful login action, I would like to navigate to the Home screen but it doesn’t work
My setup looks like the following;
App.js
import React, { Component } from 'react';
import { View } from 'react-native';
import { StackNavigator, DrawerNavigator, addNavigationHelpers } from 'react-navigation';
import { Provider, connect } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import reducers from './reducers';
import AppNavigator from './AppNavigator';
class App extends React.Component {
render() {
return (
<AppNavigator navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
})} />
);
}
}
const mapStateToProps = (state) => ({
nav: state.nav
});
const AppWithNavigationState = connect(mapStateToProps)(App);
class Root extends Component {
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={ store }>
<View style={{ flex: 1 }}>
<AppWithNavigationState />
</View>
</Provider>
);
}
}
export default Root;
NavReducer.js
import { NavigationActions } from 'react-navigation';
import AppNavigator from '../AppNavigator';
const initialState = AppNavigator.router.getStateForAction(
NavigationActions.init()
// AppNavigator.router.getActionForPathAndParams('Main')
);
export default navReducer = (state = initialState, action) => {
const nextState = AppNavigator.router.getStateForAction(action, state);
// Simply return the original `state` if `nextState` is null or undefined.
return nextState || state;
};
AppNavigator.js
import { StackNavigator, DrawerNavigator } from 'react-navigation';
import LandingPage from './components/LandingPage';
import LoginScreen from "./components/LoginForm";
import RegistrationScreen from "./components/RegistrationForm";
import Homepage from "./components/Homepage";
const LoginStack = StackNavigator({
LandingPage: { screen: LandingPage },
Login: { screen: LoginScreen },
Registration: { screen: RegistrationScreen },
}, {
headerMode: 'none',
initialRouteName: 'LandingPage'
});
const DrawerNavigatorStack = DrawerNavigator({
Home: { screen: Homepage }
}, {
headerMode: 'none',
initialRouteName: 'Home'
});
const DrawerNavigation = StackNavigator({
DrawerStack: { screen: DrawerNavigatorStack }
}, {
headerMode: 'none',
initialRouteName: 'DrawerStack'
});
const AppNavigator = StackNavigator({
LoginStack: { screen: LoginStack },
Main: { screen: DrawerNavigation }
}, {
headerMode: 'none',
initialRouteName: 'LoginStack'
});
export default AppNavigator;
Login action
export const loginUser = ({ email, password }) => {
return (dispatch) => {
dispatch({ type: LOGIN_USER });
const data = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password
})
};
const url = Globals.API_URL + 'accounts/login';
return fetch(url, data)
.then(response => {
const responseBody = JSON.parse(response._bodyText);
if (response.status === 200) {
dispatch({ type: LOGIN_USER_SUCCESS });
dispatch(NavigationActions.navigate({
routeName: ‘Home’, <=== supposed to navigate to the Home screen at this point
params: responseBody.data.access_token
}));
} else {
loginUserFail(dispatch, responseBody.message);
}
});
}
}
It successfully dispatches the LOGIN_USER_SUCCESS and the subsequent Navigation actions, but it doesn’t actually navigate to the Home screen
If I replace the ‘Home’ route with a route from the ‘LoginStack’ it will navigate to that screen with no problem. So for example, this would work
dispatch(NavigationActions.navigate({
routeName: ‘LandingPage’, <=== will successfully navigate back to the LandingPage
params: responseBody.data.access_token
}));
I’m obviously missing something, any ideas what that might be?
Thanks in advance

Related

React/Redux - TypeError: Cannot read property 'props' of undefined

i am a new in React, i am trying to create a dynamic NavBar with CoreUI. for now i have a static array in my action, so i can see it shows up with no errors on the Navigation bar.
but as soon as i run this i get an error. what i am trying to do is to create a new dynamic navigation bar and insert it into my static bar
// Admin Nav
import React, { Component } from "react";
import { getStoreType } from "../redux/actions/storeTypeActions";
import PropTypes from "prop-types";
import { connect } from "react-redux";
class AdminNav extends Component {
static propTypes = {
getStoreType: PropTypes.func.isRequired,
storeType: PropTypes.object.isRequired,
};
componentDidMount() {
this.props.getStoreType();
}
}
console.log("AdminNav", this.props);
const mapStateToProps = (state) => ({
storeType: state.storeType,
auth: state.auth,
});
export default connect(mapStateToProps, { getStoreType })(AdminNav);
//Reducer
import { GET_STORETYPE, STORETYPE_LOADING } from "../actions/types";
const initialState = {
items: [
{
title: true,
name: "ADMINISTRATOR",
wrapper: {
// optional wrapper object
element: "", // required valid HTML5 element tag
attributes: {}, // optional valid JS object with JS API naming ex: { className: "my-class", style: { fontFamily: "Verdana" }, id: "my-id"}
},
class: "", // optional class names space delimited list for title item ex: "text-center"
},
],
loading: false,
};
export default function (state = initialState, action) {
switch (action.type) {
case GET_STORETYPE:
return {
...state,
loading: false,
};
case STORETYPE_LOADING: {
return {
...state,
loading: true,
};
}
default:
return state;
}
}
//DefaultLayout.js
import React, { Component, Suspense } from "react";
import { Redirect, Route, Switch } from "react-router-dom";
import * as router from "react-router-dom";
import { Container } from "reactstrap";
import {
AppAside,
AppFooter,
AppHeader,
AppSidebar,
AppSidebarFooter,
AppSidebarForm,
AppSidebarHeader,
AppSidebarMinimizer,
AppBreadcrumb2 as AppBreadcrumb,
AppSidebarNav2 as AppSidebarNav,
} from "#coreui/react";
// Sidebar nav config (Owner/Admin)
import admin_navigation from "../_nav-admin";
// Routes Config
import routes from "../../routes";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { logout } from "../../redux/actions/authActions";
const DefaultAside = React.lazy(() => import("./DefaultAside"));
const DefaultFooter = React.lazy(() => import("./DefaultFooter"));
const DefaultHeader = React.lazy(() => import("./DefaultHeader"));
const AdminHeader = React.lazy(() => import("./AdminHeader"));
class DefaultLayout extends Component {
constructor(props) {
super(props);
this.state = {
role: "",
path: "",
dashboard: [],
};
}
loading = () => (
<div className="animated fadeIn pt-1 text-center">Loading...</div>
);
static propTypes = {
isAuthenticated: PropTypes.bool,
auth: PropTypes.object.isRequired,
logout: PropTypes.func.isRequired,
};
render() {
const { isAuthenticated } = this.props.auth;
// If NOT Authenticated, redirect to login
if (!isAuthenticated) {
this.props.history.push("/login");
}
const role = this.props.auth.user.role;
return (
<div className="app">
<div className="app-body">
<AppSidebar fixed display="lg">
<AppSidebarHeader />
<AppSidebarForm />
<Suspense>
<AppSidebarNav
navConfig={admin_navigation}
{...this.props}
router={router}
/>
</Suspense>
<AppFooter>
<Suspense fallback={this.loading()}>
<DefaultFooter />
</Suspense>
</AppFooter>
</div>
);
}
}
const mapStateToProps = (state) => ({
auth: state.auth,
});
export default connect(mapStateToProps, { logout })(DefaultLayout);
Here is a problem, you trying to access this not in a class method.
console.log("AdminNav", this.props);

How to fix TypeError: undefined is not an object (evaluating 'state.routes')

I'm following the react navigation documentation, react-navigation-redux-helpers's documentation, but always throw me this error. also if i erase the persistGate the error gets fixed but i need to persist some data so that shouldn't be an option
This is my store.js
import { createStore, applyMiddleware } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import { AsyncStorage } from 'react-native';
import { createReactNavigationReduxMiddleware } from 'react-navigation-redux-helpers';
import Reducer from './reducers/index';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
blackList: [],
};
const AppReducer = persistReducer(persistConfig, Reducer);
const middleware = createReactNavigationReduxMiddleware(
(state) => state.navigation,
);
export const store = createStore(AppReducer, applyMiddleware(middleware));
export const persistor = persistStore(store);
This is my app-with-state.js
import AppNavigator from './AppNavigator';
const AppNavigatorWithState = createReduxContainer(AppNavigator);
class ReduxNavigation extends React.Component {
render() {
const { state, dispatch } = this.props;
return <AppNavigatorWithState navigation={state} dispatch={dispatch} />;
}
}
const mapStateToProps = (state) => ({
state: state.navigation,
});
export default connect(mapStateToProps)(ReduxNavigation);
this is my AppNavigator.js
const Main = createStackNavigator(
{
Home: Home,
Movie: Movie,
Category: Category,
},
{
defaultNavigationOptions: {
header: Header,
},
},
);
const TabNavigator = createBottomTabNavigator(
{
Home: {
screen: Main,
navigationOptions: {
tabBarIcon: <Icon icon='🏠' />,
},
},
About: { screen: About },
Lucky: { screen: Lucky },
Profile: { screen: Profile },
},
{
tabBarOptions: {
activeTintColor: 'white',
activeBackgroundColor: '#65a721',
},
},
);
//const App = createAppContainer(TabNavigator);
export default TabNavigator;
and here is my App.js
import React from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './store';
import Loader from './src/sections/components/loader';
import ReduxNavigation from './src/app-navigator-with-state';
import { createAppContainer } from 'react-navigation';
const Navigation = createAppContainer(ReduxNavigation);
type Props = {};
export default class App extends React.Component<Props> {
render() {
return (
<Provider store={store}>
<PersistGate persistor={persistor} loading={<Loader />}>
<Navigation />
</PersistGate>
</Provider>
);
}
}
I know its too late but it should help others :))
In your mystore.js
const middleware = createReactNavigationReduxMiddleware(
(state) => state.navigation,
)
should be look like this:
const middleware = createReactNavigationReduxMiddleware(
(state) => state.router,
)
I also got this error and I didn't find any clue, and stuck. After several hours of debugging, it was coz of my stupid mistake.
This was my Wrong Case:
const customContent = ({props}) => { }
Acutally, props doesn't need {}. Just call (props) like and error was fixed.
This is Right Case:
const customContent = (props) => { }
Please Don't add {} when you call props.
Hope it helps for someone who got error like me.
I also got this error and it was because i accidentally called:
navigation.pop("nameOfScreen");
I forgot to change "pop" when I changed from pop(1) to navigate("")
Maybe this will help someone else who is as tired as I am rn.

undefined is not an object (evaluating 'action.routeName') while using React-Navigation and Redux for React-Native App

I'm getting the following error (articulated above and noted in the screenshot here) for a React Native app. I'm implementing react-navigation into redux.
I also haven't put in any redirects into the app yet. I'm planning on calling NavigationActions to redirect to the Login screen based on the LoggedIn status which is being configured by a separate reducer that manages the state for the user.
The app was working properly when I did not have redux managing the navigation state. I decided to put the navigation state into redux when I realized I'll need some redirects based on the user logged in status which is being managed by the redux.
My code is as follows:
src/navigators/middleware.js
import {
createNavigationPropConstructor,
createReactNavigationReduxMiddleware,
} from 'react-navigation-redux-helpers';
// building redux utils for navigation
export const middleware = createReactNavigationReduxMiddleware(
'root',
state => state.nav,
);
export const navigationPropConstructor = createNavigationPropConstructor('root');
src/navigators/AppNavigator.js
import React from 'react';
import { StackNavigator } from 'react-navigation';
import Welcome from '../screens/Welcome';
import Dashboard from '../screens/Dashboard';
import Login from '../screens/Login';
routeNames = {
Welcome: { screen: Welcome },
Dashboard: { screen: Dashboard },
Login: { screen: Login },
};
config = {
navigationOptions: ({
header: 'null',
headerStyle: {
backgroundColor: 'white',
borderBottomWidth: 0,
},
headerLeft: null,
headerTitleStyle: {
fontSize: 30,
fontFamily: 'Roboto-Bold',
},
}),
};
export const AppNavigator = StackNavigator(routeNames, config);
src/navigators/AppWithInternalState.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addNavigationHelpers } from 'react-navigation';
import { AppNavigator } from './AppNavigator';
import { initializeListeners } from 'react-navigation-redux-helpers';
import { navigationPropConstructor } from './middleware';
class AppWithInternalState extends React.Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
nav: PropTypes.object.isRequired,
};
componentDidMount = () => {
initializeListeners('root', this.props.nav);
};
render = () => {
const { dispatch, nav } = this.props;
const navigation = navigationPropConstructor(dispatch, nav);
return <AppNavigator navigation={ navigation } />;
};
}
const mapStateToProps = state => ({
nav: state.nav,
});
export default connect(mapStateToProps)(AppWithInternalState);
src/reducers/navReducers
import { AppNavigator } from '../navigators/AppNavigator';
import { NavigationActions } from 'react-navigation';
const router = AppNavigator.router;
const firstAction = router.getActionForPathAndParams('Dashboard');
const tempNavState = router.getStateForAction(firstAction);
const secondAction = router.getActionForPathAndParams('Login');
const initialNavState = router.getStateForAction(secondAction, tempNavState);
export default navReducer = (state=initialNavState, action) => {
let nextState;
switch (action.type) {
case 'Login':
nextState = router.getStateForAction(
NavigationActions.back(),
state,
);
break;
default:
nextState = router.getStateForAction(action.state);
break;
}
};
I was able to solve this myself. Looks like there is an issue with react-navigation when using createNavigationPropConstructor.
This will not be solved until react-navigation#2.03 is released.
Until then, create your own navigation prop:
import { createReduxBoundAddListener } from 'react-navigation-redux-helpers';
const navigation = {
dispatch,
state: nav,
addListener: createReduxBoundAddListener('root'),
};
You can see and track the issue here: https://github.com/react-navigation/react-navigation/issues/4320

How to use StackNavigator with Redux?

Could please somebody help me to manage with StackNavigator and Redux integration? Everything looks pretty simple, but doesn't work.
index.ios.js
import React from 'react'
import {
AppRegistry
} from 'react-native'
import { Provider } from 'react-redux'
import configureStore from './configureStore'
import { StackNavigator } from 'react-navigation';
import Welcome from "./screens/welcome";
import Accounts from "./screens/accounts";
const store = configureStore()
const Nav = StackNavigator({
Welcome: {
screen: Welcome,
},
Accounts: {
screen: Accounts,
},
});
const TestApp = () => (
<Provider store={store}>
<Nav />
</Provider>
)
AppRegistry.registerComponent('TestApp', () => RNRedux)
configureStore.js
import { createStore } from 'redux'
import rootReducer from './reducers'
export default function configureStore() {
let store = createStore(rootReducer)
return store
}
reducers/index.js
import { combineReducers } from 'redux'
import accounts from './accounts'
const rootReducer = combineReducers({
accounts
})
export default rootReducer
screens/accounts.js
import React from 'react';
import { StyleSheet, Text, View, button } from 'react-native';
import { ListItem } from 'react-native-elements';
import { StackNavigator } from 'react-navigation';
import { connect } from 'react-redux';
export class Accounts extends React.Component {
static navigationOptions = {
title: 'Accounts',
}
constructor(props) {
super(props);
}
render() {
state = {}
const { navigate } = this.props.navigation;
return (
<View>
{
this.props.accounts.map((l, i) => (
<ListItem
key={i}
title={l.title}
subtitle={l.hash}
/>
))
}
</View>
);
}
}
function mapStateToProps (state) {
return {
accounts: state.accounts
}
}
export default connect(
mapStateToProps,
)(Accounts)
reducers/accounts.js
const initialState = {
accounts: [
{
title: "Bitcoin Slash Fund",
hash: "0x83247jfy344fgg",
},
],
}
export default function (state = initialState, action) {
switch (action.type) {
default:
return state;
}
}
When I navigate to Accounts screen, I get the error
TypeError: undefined is not a function (near '...this.props.state.accounts.map...');
Accounts screen seems not to be actually connected to Redux, and I can't figure out why. Any ideas? Thanks a lot.
Try this one:
function mapStateToProps (state) {
// Just FYI here you can use console.log to see the state)
// console.log(state);
return {
accounts: state.accounts.accounts
}
}
you could see console.log output in Xcode or in AndroidStudio.
Don't use Redux to manage the state of navigator. refer to this official doc: https://reactnavigation.org/docs/en/redux-integration.html
In my case, if you just want the title of navigator changed when the Redux state changes, just use screenProps, refer to: Passing screenProps to a tab navigator
e.g. in your App.js render method, pass screenProps into the target component,
import { LoginStackNavigator } from './navigators/LoginStackNavigator'
render () {
return (
<LoginStackNavigator screenProps={
{
// Step1. pass the value into the navigator component instance.
tradeTitle: i18n.t('trade', {locale: this.props.language}),
}
}/>
)
}
and in the related file, ( such as LoginStackNavigator.js in my case),
import { AppTabNavigator } from '../navigators/AppTabNavigator'
export const LoginStackNavigator = createStackNavigator({
Trade: {
screen: AppTabNavigator
}
//...
and in the final file ( AppTabNavigator)
export const AppTabNavigator = createBottomTabNavigator({
TradeStackNavigator: {
screen: TradeStackNavigator,
navigationOptions: ({navigation, navigationOptions, screenProps}) => {
return {
// Step2. here use screenProps to retrieve the value passed in .
tabBarLabel: screenProps.tradeTitle,
}
}

React Native Navigation with Redux - undefined is not a function

I try to setup react-native-navigation but I tun in problem
My code is following
app.js
import React from 'react';
import { Provider } from 'react-redux'
import { Navigation } from 'react-native-navigation';
import registerScreens from './screens'
import configureStore from './src/store/configureStore';
export default class App extends React.Component {
constructor(props) {
super(props)
const store = configureStore()
registerScreens(store, Provider);
startApp()
}
startApp() {
Navigation.startSingleScreenApp({
screen: {
screen: 'ior.Login',
title: 'Welcome',
navigatorStyle: {},
navigatorButtons: {}
},
drawer: {} ,
passProps: {},
animationType: 'slide-down'
});
}
}
configureStore.js
import ReduxThunk from 'redux-thunk'
import reducers from '../reducers'
import { createStore, applyMiddleware } from 'redux';
export default function configureStore() {
return createStore(
reducers,
{},
applyMiddleware(ReduxThunk)
);
}
screens.js
import { Navigation } from 'react-native-navigation';
import Login from './src/components/Login'
export function registerScreens(store, Provider) {
Navigation.registerComponent('ior.Login', () => Login, store, Provider);
}
Login.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { StyleSheet, Text, View, TextInput, Button } from 'react-native';
import { loginChanged, passwordChanged, loginUser } from '../actions';
class Login extends React.Component {
onLoginChange(text) {
this.props.loginChanged(text)
}
onPasswordChange(text) {
this.props.passwordChanged(text)
}
onPress() {
this.props.loginUser(this.props.email, this.props.password)
}
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.textField}
onChangeText={this.onLoginChange.bind(this)}
value={this.props.email}
placeholder={"Логин"}
/>
<TextInput
style={styles.textField}
onChangeText={this.onPasswordChange.bind(this)}
value={this.props.password}
placeholder={"Пароль"}
/>
<Button onPress={this.onPress.bind(this)} title={"Войти"}/>
</View>
)
}
}
const styles = StyleSheet.create({
textField: {
flex: 1,
width: '80%',
height: 100,
},
container: {
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
flex: 0.3,
marginTop: 210
},
button: {
width: '100%'
}
});
const mapStateToProps = state => {
return {
email: state.login.email,
password: state.login.password
}
}
export default connect(mapStateToProps, { loginChanged, passwordChanged, loginUser })(Login)
actions/index.js
import axios from 'axios'
export const loginChanged = (text) => {
return {
type: 'LOGIN_CHANGED',
payload: text
}
}
export const passwordChanged = (text) => {
return {
type: 'PASSWORD_CHANGED',
payload: text
}
}
export const loginUser = (email, password) => {
const creds = { mail: email, password: password }
console.log(creds)
return (dispact) => {
axios.post('http://192.168.1.10:3000/users/auth', creds)
.then(response => console.log(response))
.catch( err => console.log(err))
}
}
What am I doing wrong ?
The issue is that registerScreens is exported as a named export but you're importing it as a default export.
import registerScreens from './screens'
// ^ this is how you import a default export
You should add export default to registerScreens
export default function registerScreens(store, Provider) {
// ...
}
Or import it like a named export:
import { registerScreens } from './screens'
Additionally, you are calling a class method startApp() as if it was a normal function but it's a method on your class.
export default class App extends React.Component {
constructor(props) {
// ...
startApp()
// ^calling like a simple function
}
}
You must call it from the context:
export default class App extends React.Component {
constructor(props) {
// ...
this.startApp()
// ^calling it like a method
}
}

Categories

Resources