Simple implementation of react native screen change - react-native

I am new at react native and i am trying to implement the navigation from one screene to the other and it is a bit hard because sources are old and do not work as possible solutions for current react native version, i know that this question is not the best question to make here but i rally need help

navigation you can do something like this. lets have quick look at example:
RootStack.js
import createAnimatedSwitchNavigator from 'react-navigation-animated-switch';
import { withNavigation } from 'react-navigation';
const RootStack = createAnimatedSwitchNavigator(
{
splash:SplashScreen,
second:SecondScreen,
},
{
initialRouteName: splash
}
)
export default RootStack;
APP.js
import { createStackNavigator } from 'react-navigation-stack';
import AuthStack from './AuthStack'
const RootStack = createStackNavigator({ RootStack});
const AppContainer = createAppContainer(RootStack);
export default AppContainer;
your component should be like this.
...rest
const SplashScreen = (props) =>{
return (
<View>
<TouchableOpacity onPress={()=>{
props.navigation.navigate("second")
}}></TouchableOpacity>
</View>
)
}
export default withNavigation(SplashScreen)

Related

Too many re-render errors in react-native using expo

I am getting an error randomly when I start my expo app and it says:
It says that the error is here and I am not sure what is causing it. (it wasn't there before)
import React from "react";
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createBottomTabNavigator } from "react-navigation-tabs";
import AccountScreen from "./src/screens/AccountScreen";
import CreateScreen from "./src/screens/CreateScreen";
import HomeScreen from "./src/screens/HomeScreen";
import ItemDetailScreen from "./src/screens/ItemDetailScreen";
import SigninScreen from "./src/screens/SigninScreen";
import SignupScreen from "./src/screens/SignupScreen";
import { Provider as AuthProvider } from "./src/context/AuthContext";
import { setNavigator } from "./src/navigationRef";
const switchNavigator = createSwitchNavigator({
loginFlow: createStackNavigator({
Signup: SignupScreen,
Signin: SigninScreen
}),
mainFlow: createBottomTabNavigator({
itemListFlow: createStackNavigator({
Home: HomeScreen,
ItemDetail: ItemDetailScreen
}),
Create: CreateScreen,
Account: AccountScreen
})
});
const App = createAppContainer(switchNavigator);
export default () => {
return (
<AuthProvider>
<App
ref={navigator => {
setNavigator(navigator)
}}
/>
</AuthProvider>
);
};
The app renders, then the App component calls setNavigator with its current ref, then rerenders as a result of whatever is going in your setNavigator function, and repeats forever until the call stack reaches a maximum depth.
It's difficult to answer exactly what's going on without being able to look at that function. But in general, you shouldn't have to use the ref at all anyway. Simply <App /> should be fine from what I can see, since you already initialize it as a switchNavigator.

Cannot access redux props inside react-navigation v3 tab navigator (getting error this.props.<function_name> is not a function)

I am having trouble connecting the tab navigator (from React-Navigation v3) to the redux provider.
So this is how my react-navigation and redux is configured:
app/
/react-redux provider
/app-container (this is the AppContainer of the main SwitchNavigator)
/welcome-screen
/login-screen
/register-screen
/home-navigator (this is the TabNavigator that is inside the SwitchNavigator)
Home navigator holds the screens to which user is directed to when he logs-in. In the first 3 screends (welcome, login and register) I can access the functions that are "connected" from redux to the screen through standard mapDispatchToProps.
This is the app component:
/**
* Entry point for the app
*/
import React, { Component } from "react";
// redux
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import reduxThunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import main_app_reducer from "./modules/core/reducers/main_app_reducer";
// create redux store
const create_store = composeWithDevTools(applyMiddleware(reduxThunk))(createStore);
export const store = create_store(main_app_reducer);
// navigation
import AppContainer from "./modules/core/components/AppNavigator";
import { configure_axios } from "./helpers/axios_config";
configure_axios();
class App extends Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>
);
}
}
export default App;
And then, from there we go to AppContainer:
/**
* this components ensures app navigation so that user can jump from one screen to another
*/
// navigation
import { createSwitchNavigator, createAppContainer } from "react-navigation";
// screens
import WelcomeScreen from "../screens/WelcomeScreen";
import LoginScreen from "../../auth/screens/LoginScreen";
import RegisterScreen from "../../auth/screens/RegisterScreen";
import HomeNavigator from "./HomeNavigator";
const AppSwitchNavigator = createSwitchNavigator({
// for users that are not logged in yet
Welcome: { screen: WelcomeScreen },
Login: { screen: LoginScreen },
Register: { screen: RegisterScreen },
// for logged in users
HomeNavigator: { screen: HomeNavigator },
});
const AppContainer = createAppContainer(AppSwitchNavigator);
export default AppContainer;
All of the code above works perfectly with no errors, the problem occurs inside the HomeNavigator component that you see below.
This is the HomeNavigator component:
import { createBottomTabNavigator } from "react-navigation";
import { HomeScreen } from "../screens/HomeScreen";
import { DashboardScreen } from "../screens/DashboardScreen";
const HomeNavigator = createBottomTabNavigator(
{
Home: { screen: HomeScreen },
Dashboard: { screen: DashboardScreen },
},
{
navigationOptions: ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
return {
headerTitle: routeName,
};
},
},
);
export default HomeNavigator;
NONE of the screens inside the HomeNavigator are connected to Redux altough they are defined THE SAME WAY as the screens inside AppContainer file. For comparison let's see Login screen from AppContainer and Home screen from HomeNavigator:
LoginScreen:
import React, { Component } from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { get_user_servers } from "../actions/core_actions";
export class LoginScreen extends Component {
componentDidMount() {
this.props.get_user_servers(); // this function works absolutely fine
}
render() {
return (
<View>
<Text> LoginScreen </Text>
</View>
);
}
}
const mapStateToProps = (state) => ({});
const mapDispatchToProps = { get_user_servers };
export default connect(
mapStateToProps,
mapDispatchToProps,
)(LoginScreen);
HomeScreen:
import React, { Component } from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { get_user_servers } from "../actions/core_actions";
export class HomeScreen extends Component {
componentDidMount() {
this.props.get_user_servers();
// the same function as in LoginScreen but here the function does not work
// I'm getting an error = TypeError: this.props.get_user_servers is not a function (see picture below)
}
render() {
return (
<View>
<Text> HomeScreen </Text>
</View>
);
}
}
const mapStateToProps = (state) => ({});
const mapDispatchToProps = { get_user_servers };
export default connect(
mapStateToProps,
mapDispatchToProps,
)(HomeScreen);
That function (get_user_servers) is defined properly and it works fine in LoginScreen.
thanks everyone who took their time to help me, in the end it was my mistake that I overlooked. If you check out the third code-block from this question you can see that I import my components like this:
import { HomeScreen } from "../screens/HomeScreen";
import { DashboardScreen } from "../screens/DashboardScreen";
Which is wrong, I changed that to:
import HomeScreen from "../screens/HomeScreen";
import DashboardScreen from "../screens/DashboardScreen";
And now everything works fine, thanks again :)
Assuming it's the same function you're importing, please could you try to check your import of get_user_servers function from both screen : LoginScreen and HomeScreen. According to your code it look like LoginScreen ("../../auth/screens/LoginScreen") and HomeScreen ("../screens/HomeScreen") are not in the same path.
As asked above, could check the path of the files, or post it so we can help. Also could you open the remote debugger, and inside the componentWillMount you can put:
console.log(this.props)
to check if the HomeScreen is geting the function inside props.

invariant violation element type is invalid expected a string react native [duplicate]

This question already has answers here:
createStackNavigation invariant violation element type is invalid expected a string
(2 answers)
Closed 4 years ago.
So this is my first application inside react-native and I'm running into the following error.
I've tried working on this bug for the past few days but haven't had much luck.
Below is a copy of my MainNavigator.js:
import DlLoading_2 from "./src/screens/DlLoading_2";
import DlMain from "./src/screens/DlMain";
import { createStackNavigator, createAppContainer } from "react-
navigation";
const MainNavigator = createStackNavigator({
DlLoading_2: {
screen: DlLoading_2
},
DlMain: {
screen: DlMain
}
},
{
headerMode: "none"
}
);
export default createAppContainer(MainNavigator);
render() ;
return (
< MainNavigator />
) ;
And here is a copy of my opening page:
import React, { Component } from "react";
import { Center } from "#builderx/utils";
import { View, StyleSheet, Image, Text } from "react-native";
import { createAppContainer } from 'react-navigation';
import { MainNavigation } from '../screens/MainNavigator';
import { TouchableHighlight } from 'react-native'
import { AppContainer } from "../screens/MainNavigator"
const AppContainer = createAppContainer(MainNavigation);
export default class DlLoading_2 extends Component {
render() {
return (
<AppContainer/>
<View style={styles.root}>
<Center />
<TouchableHighlight onPress={() =>
this.navigation.navigate('DlMain')}/>
<Image style={styles.blueDisk} source= .
{require('../assets/ComponentTMP_0-image.jpg')}/>
<TouchableHighlight/>
<Center horizontal>
<Image
source={require("../assets/ComponentTMP_0-
image2.png")}
style={styles.dlLogo}
/>
</Center>
<Center horizontal>
<Text style={styles.text}>TRANSINDENTAL
MEDITATION</Text>
</Center>
<AppContainer/>
</View>
)
}
}
Any help on this error would be greatly appreciated! Thanks in advance.
There are few things going wrong in this. Let's take a look each file in turn
MainNavigation.js
You've set up your MainNavigator correctly however you don't set up the AppContainer that way.
This is how I would set up your MainNavigation.js
import Screen1 from './Screen1';
import Screen2 from './Screen2';
import { createStackNavigator, createAppContainer } from 'react-navigation';
const screens = {
Screen1: {
screen: Screen1
},
Screen2: {
screen: Screen2
}
}
const config = {
headerMode: 'none',
initialRouteName: 'Screen1'
}
const MainNavigator = createStackNavigator(screens, config);
export default createAppContainer(MainNavigator);
I prefer to separate everything out so that it is easy to see what everything is. The createAppContainer just wraps the MainNavigator you don't need to set a render function like you have done, as it is not being used and may lead to code errors.
In the options for the MainNavigator you can set your initalRouteName this is where the app will open on. If you want to open it on Screen2 set it accordingly, if you don't set it it will default to the first one in the list.
App.js
You have put in your AppContainer but then you have this <View> underneath it that is comprised of many things, including another AppContainer, where many of the tags are not closed properly.
I think that what is in the View should be on another screen in your MainNavigator, with that screen set as your initialRouteName.
This is how I would setup the App.js, you don't really need much more here.
import React, {Component} from 'react';
import AppContainer from './MainNavigation';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<AppContainer />
)
}
}
Here is a snack that allows you to navigate from Screen1 to Screen2 and back
https://snack.expo.io/r1FqD8VX4
Closing tags
When you open tags for a component, like View they are opened like this
<View>
When you close the tags for that View they are closed like this
</View>
Anything that is contained between those tags are called that component's children, and are accessed inside that component by this.props.children.
Not all components need to take children, like the Button component. It is opened and closed with the one tag like so
<Button onPress={} title={'title'} />
If you are looking at using TouchableHighlight this is how you would write the code so that it wraps your Image correctly
<TouchableHighlight onPress={() => this.props.navigation.navigate('DlMain')}>
<Image style={styles.blueDisk} source={require('../assets/ComponentTMP_0-image.jpg')}/>
</TouchableHighlight>

React navigation. Render extra views on top of navigator

I'm trying to create a React Native app that renders an area with interchangeable screens and fixed view with some additional data/menu. I tried this solution form official React Navigation, but I can't make it work.
import React, { Component } from "react";
import {createStackNavigator} from 'react-navigation';
import { Text, View,} from 'react-native';
import Details from './DetailsScreen';
import MainScreen from './MainScreen';
const RootStack = createStackNavigator({
Main: {screen: MainScreen,
navigationOptions: {
header: null
}
},
Details: {
screen: Details,
},);
class App extends Component {
static router = {
...RootStack.router,
getStateForAction: (action, lastState) => {
return MyStack.router.getStateForAction(action, lastState);
}
};
render() {
const { navigation } = this.props;
return(
<View>
<Text>Foo</Text> //this is rendering
<RootStack navigation={navigation}/> //this is not
</View>);
}
}
export default App;
Article form link suggests that I can wrap object created with createStackNavigator() in a parent View, but it renders only when it is the only thing returned from render(), otherwise it seems to be ignored. Example from link claims that it is possible to "render additional things", but I can't make it work. Is it possible to do this way?
You can try this:
//wrapper.js
function wrapNavigator(Navigator, Wrapper, wrapperProps = {}) {
const WrappedComponent = props => (
<Wrapper { ...props, ...wrapperProps}>
<Navigator {...props} />
</Wrapper>
);
WrappedComponent.router = Navigator.router;
WrappedComponent.navigationOptions = Navigator.navigationOptions;
return WrappedComponent;
};
//app.js
const App = (props) => <View>
<Text>Some text...</Text>
{children}
</View>
export default wrapNavigator(Stack, App);
But this will not work if there are no parent navigator for App component.

Undefined is not an object React Native StackNavigator

I have been trying to get a simple React Native StackNavigation example app working, however I keep getting an
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')
I am not expecting the app to navigate anywhere at this stage, simply deploy with an app bar and some arbitrary text.
import React, { Component } from 'react';
import {AppRegistry, Text} from 'react-native';
import {StackNavigator} from 'react-navigation';
export default class App extends React.Component {
static navigationOptions = {
title: 'Home',
};
render() {
const { navigate } = this.props.navigation;
return (
<Text> Hello World </Text>
);
}
}
const appScreens = StackNavigator({
Home: {screen: App},
})
AppRegistry.registerComponent('IntervalTimer', () => appScreens);
The error is reporting on the const { navigate } = this.props.navigation; declaration. And removing this line does allow the app to deploy but with no header as I would expect.
StackNavigator was installed using NPM and is being imported into the app fine.
There are similar questions posted and I have tried their suggestions. Appreciate any help you can offer!
You can add initialRouteName on StackNavigator's option. Try this.
import React, { Component } from 'react';
import {AppRegistry, Text} from 'react-native';
import {StackNavigator} from 'react-navigation';
class App extends React.Component {
static navigationOptions = {
title: 'Home',
};
render() {
const { navigate } = this.props.navigation;
return (
<Text> Hello World </Text>
);
}
}
export const appScreens = StackNavigator({
Home: { screen: App }
},{
initialRouteName: Home
})
AppRegistry.registerComponent('IntervalTimer', () => appScreens);
If this is just that the prop might have a chance of being undefined, you can just check for undefined.
const { navigate } = this.props.navigation || {};
Assuming at some point the navigation is defined in render, the above should be safe to use. You can try logging it and see if it is always undefined or it gets defined at some point.
console.log(navigate)
The output might be...
undefined
undefined
//defined