Navigate to completely different screen on React Native - reactjs

On my React Native app I am initially loading SceneA, which simply displays a text "Click me". When this button is clicked I would like to load a completely different screen (SceneB) that has completely different components.
All the examples that I found online (like the example below) load a scene with exactly the same components, but different values. In my case it is a completely different layout. How can I navigate to that new screen (SceneB)?
It is basically the equivalent to a new Activity on Android, passing some data at the same time. Any pointers will be appreciated.
index.android.js
import React, { Component } from 'react';
import { AppRegistry, Navigator } from 'react-native';
import SceneA from './SceneA';
class ReactNativeTest extends Component {
render() {
return (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) =>
<SceneA
title={route.title}
// Function to call when a new scene should be displayed
loadNewScene={() => {
const nextIndex = route.index + 1;
navigator.push({
title: 'Scene B',
index: nextIndex,
});
}}
/>
}
/>
)
}
}
AppRegistry.registerComponent('ReactNativeTest', () => ReactNativeTest);
SceneA.js
import React, { Component, PropTypes } from 'react';
import { View, Text, TouchableHighlight } from 'react-native';
export default class SceneA extends Component {
render() {
return (
<View>
<Text>Scene A</Text>
<TouchableHighlight onPress={this.props.loadNewScene}>
<Text>Click Me</Text>
</TouchableHighlight>
</View>
)
}
}
SceneA.propTypes = {
loadNewScene: PropTypes.func.isRequired,
};

You handle which components should render in the renderScene function, each scene will have a route.title so you can decide which to render based on that.
renderScene={(route, navigator) =>
if (route.title === 'Scene A') {
return <SceneA navigator={navigator} />
}
if (route.title === 'Scene B') {
return <SceneB navigator={navigator} />
}
}
Then inside your components you're gonna have a function that handles the navigation:
navigateToSceneB = () => {
this.props.navigator.push({
title: 'Scene B'
})
}

Related

React Native - render a component onClick on an Icon

A part of my app has an 'icon'. When I 'click' on the icon, the State of the parent component changes to 'true' and I want a new 'Component' to render saying 'I am a new Component'. I am trying like this below, there is no error showing at the debugger. The Icon is an image component that I am importing. Here is the Code.
This is the parent Component
import React, {Component} from 'react';
import {View} from 'react-native';
import {Icon} from '../ui/Icon';
type HomeSceneState = {
calendarState:boolean
}
class HomeScene extends Component<HomeSceneState> {
state = {
calendarState:false
}
openCalendar = () => {
console.log("open calendar")
this.setState({
calendarState : true
})
}
render() {
return (
<View style={{marginBottom: spacing.double,
backgroundColor:"black", flexDirection:"row"
}}>
<View>
<Icon onPress = {() => this.openCalendar()} />
{this.calendarState ? <Casie/> : null }
</View>
</View>
);
}
}
export default HomeScene;
The Children Component looks like below
class Casie extends Component<CalendarProps> {
render() {
return (
<View>
I am a new Component
</View>
);
}
}
export default Casie;
replace <Calendar/> by your child component name <Casie/> (in your case). It seems you are not rendering your child component when the state changes.
In your parent component you import the react native navigation.
after you can use useNavigation for navigate the page. Sorry my english.
import { useNavigation } from '#react-navigation/native'
class HomeScene extends Component<HomeSceneState> {
state = {
calendarState:false
}
openCalendar = () => {
console.log("open calendar")
navigation.navigate('Casie')
}
render() {
return (...)
}
}
export default HomeScene;

Why would a react-native view not update after render has successfully run?

I have a component DeckListView which I navigate to after updating state with redux. When I use the debugger in chrome I can see the this.props.Decks.map((deck) loop going through successfully with a list of data, but when I see the screen I don't see the additional Text. Any idea what may be happening?
I have what I believe to be the key code snippets below. The rest can be found at https://github.com/wcwcaseman/mobile-flashcards
Reducer
case ADD_DECK :
return {
...state,
[action.deck.title]:action.deck,
}
Navigation
homePage = () => {
this.props.navigation.navigate('DeckListView');
}
Actual page
import React, { Component } from 'react';
import { View, Text} from 'react-native';
import { connect } from 'react-redux'
class DeckListView extends Component {
render() {
return (
<View>
<Text>Toast the world</Text>
{this.props.Decks.map((deck) => {
<Text key={deck} >item</Text>
})}
</View>
);
}
}
function mapStateToProps ({ decks }) {
let Decks = [];
if(decks !== {} && decks !== null)
{
Decks = Object.keys(decks);
}
return {
Decks: Decks
}
}
export default connect(mapStateToProps)(DeckListView)
You need to return from the map function
{this.props.Decks.map((deck) => {
return <Text key={deck} >item</Text>
})}

Unable to use StackNavigator in ReactNative

I'm trying to create a simple navigation in the following page:
Page1:
import React, { Component } from 'react';
import { Text, View, TouchableOpacity, Alert } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { connect } from 'react-redux';
var styles = require('./styles');
class Page1 extends Component {
static navigationOptions = {
header: null
};
componentDidMount() { // <== Edited
setTimeout(function() {
const { navigate } = this.props.navigation;
},4000);
}
render() {
const { navigate } = this.props.navigation; // <= Getting error here
const { fname, lname } = this.props.person;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
From Page 1 - {lname} { fname}
</Text>
<TouchableOpacity
// onPress={() => this.props.navigation.navigate('Page2', { user: 'Lucy' }) }
>
<Text style={styles.welcome}> click for Page 2</Text>
</TouchableOpacity>
</View>
);
}
}
function mapStateToProps(state) {
return {
person:state.person
}
}
export default connect(mapStateToProps) (Page1);
Page 3:
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import Page1 from './Page1'
import { Provider, connect } from 'react-redux'
import configureStore from './store'
const store = configureStore()
export default class Page3 extends Component {
render() {
return (
<Provider store={store}>
<Page1 />
</Provider>
);
}
}
And in the index page I'm importing Page1, Page2 and Page3 and :
const SimpleApp = StackNavigator({
Page1: { screen: Page1 },
Page2: { screen: Page2 },
Page3: { screen: Page3 },
});
AppRegistry.registerComponent('my03', () => SimpleApp);
The app works fine unless I comment const { navigate } = this.props.navigation;. I get the following error:
Undefined is not an object (evaluating 'this.props.navigation.navigate')
I also tried:
onPress={() => this.props.navigation.navigate('Page2', { user: 'Lucy' }) } and
onPress={() => navigation.navigate('Page2', { user: 'Lucy' }) }
Not really sure why I tried it but was going to figure it out if it worked. It did not.
I'm trying to use ReactNavigation without creating the reducer for it, cause I did not understand this part even after trying for 2 days.
Why is this failing here? Please help.
Many thanks.
UPDATE1
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Page1 from './src/components/Page1'
import Page2 from './src/components/Page2'
import Page3 from './src/components/Page3'
const SimpleApp = StackNavigator({
Page3: { screen: Page3 },
Page2: { screen: Page2 },
Page1: { screen: Page1 },
});
AppRegistry.registerComponent('my03', () => SimpleApp);
Short answer. Just do this. <Page1 navigation={this.props.navigation} />
Explanation - The reason why this.props.navigation is coming out undefined is that you're essentially using another instance of the Page 1 component inside your Page 3 and not the one that you used to initialize the StackNavigator with. So it's an entirely new Page 1 that is not coupled with the StackNavigator at all. If Page 1 would have been the starting component of your StackNavigator. Then this.props.navigation would not have been undefined which brings me to another point of interest.
Why would you ever nest Page 1 inside Page 3 but want the same page as a sibling to Page 3 inside your react navigation stack? The idea is to add components inside our StackNavigator as screens without nesting them together and we move from one screen to another using this.props.navigation.navigate inside any one of them. So, therefore, our Page 3 would have our navigation prop (since I'm assuming it gets loaded first through the StackNavigator directly) we just pass that prop to our nested Page 1 component and viola! You would now have access to this.props.navigation inside your Page 1.
Also, since your Page 3 has the <Provider > tag I'm assuming it's something more of a root. In that case, you're better off using <SimpleApp > in place of <Page1 > and keeping Page 1 as the starting point of your Stack. You can then register your root component as AppRegistry.registerComponent('my03', () => Page3);
The last piece of info, you can keep your redux state and your navigation completely decoupled from each other so use redux integration only when you're absolutely sure that you need your navigation state inside your redux store. A project which has both Redux and ReactNavigation doesn't mean that you have to integrate them both. They can be completely separate.
Phew! Hope it helps! :)

Pass TextInput props between different screens in React Navigation

I am totally lost on how to grab two parameters from a form screen and pass them via React Navigator and display them on the previous screen.
The app section in question works like this:
1. touchablehighlight to form screen.
2. input title and description and press submit onpress
3. the onpress runs a function that dispatches the parameters to the previous page via a key.
4. then returns back to the origin page, with the props on display.
I am having multiple issues with the process:
1. if I am understanding the docs correctly, each page has a unique key and i tried to find it via this.props.navigation.state.key, however unknown to me, on refresh the id number would change.
2. that leads to problem 2 where the function will run, but it will not redirect back to the original page.
3. i have tried .navigate line after .dispatch but it would open a new copy of the original page and not display the new props that supposively were passed down.
import React from 'react';
import styles from '../styling/style.js';
import { Text, View, Image, TouchableHighlight, TextInput, Alert } from 'react-native';
import { StackNavigator, NavigationActions } from 'react-navigation';
import Forms from './formGenerator';
export default class Workout extends React.Component {
constructor(props) {
super(props);
this.state = {
programTitle: '',
programDescription: ''
}
}
render() {
const {navigate} = this.props.navigation;
return (
<Image style={styles.workoutContainer, { flex: 1}} source={require("../images/HomepageBackground.jpg")}>
<View style={styles.workoutBody}>
<Text style={styles.workoutTextBody}> {this.state.programTitle}</Text>
<Text style={styles.workoutTextBody}>{this.state.programDescription}</Text>
</View>
<View style={styles.createButton}>
<TouchableHighlight onPress={Alert.alert(this.props.navigation.state.key)} style={styles.addButtonTouch} title='test' >
<Text style={styles.addButtonText}>+</Text>
</TouchableHighlight>
</View>
</Image>
);
}
// End of the render
}
import React from 'react';
import styles from '../styling/style.js';
import { Text, View, Image, TouchableHighlight, TextInput, Button, Alert } from 'react-native';
import Workout from './workouts';
import { NavigationActions } from 'react-navigation';
export default class Forms extends React.Component {
constructor(props) {
super(props);
this.state = {
programTitle: '',
programDescription: ''
}
}
render() {
const {goBack} = this.props.navigation;
const {params} = this.props.navigation.state;
return (
<Image style={styles.workoutContainer, { flex: 1}} source={require("../images/HomepageBackground.jpg")}>
<View style={styles.workoutBody}>
<Text style={styles.formHeader}>Program Title</Text>
<TextInput
autoFocus={true}
style={styles.formBody}
onChangeText={(programTitle) => this.setState({programTitle})}
placeholder='Title'
value={this.state.programTitle} />
<Text style={styles.formHeader}>Description (Ex. 4sets x 10reps)</Text>
<TextInput
autoFocus={true}
style={styles.formBody}
placeholder='Description'
onChangeText={(programDescription) => this.setState({programDescription})}
value={this.state.programDescription} />
<TouchableHighlight onPress={this.addProgram} style={styles.buttonBody} title="Add Program" >
<Text>Add Program</Text>
</TouchableHighlight>
</View>
</Image>
);
}
addProgram = () => {
Alert.alert(this.props.navigation.state.key);
this.setState({programTitle: ''});
this.setState({programDescription: ''});
const setParamsAction = NavigationActions.setParams({
params: { programTitle: this.state.programTitle, programDescription: this.state.programDescription },
key: ,
})
this.props.navigation.dispatch(setParamsAction)
};
}
If you are trying to get parameter from "Next Page", you could have two approaches.
1, save the params in AsyncStorage (suggested)
2, using navigation setParams function with the params
const setParamsAction = NavigationActions.setParams({
params: { title: 'Hello' },
key: 'screen-123',
})
this.props.navigation.dispatch(setParamsAction)
https://reactnavigation.org/docs/navigators/navigation-actions
You are just trying to display information from the Forms class on the Workout class, correct??
From your Workout class, create a function that update's it's state.
updateWorkoutState = (programTitle,programDescription) => this.setState(programTitle,programDescription)
Pass that function through to the Forms class when you push that route.
this.props.navigation.navigate('Forms',{updateWorkoutState: this.updateWorkoutState}
Once your conditions are met on the Forms class and you want to update the Workout component, call it with this.props.navigation.state.params.updateWorkoutState(val1,val2)
Do not use AsyncStorage for this.

Undefined navigator.push React-native 0.43.4

I am using the Navigator component of react-native but i still get error when i want to push to anthor page push undefined is not a function so there is my code
import React, { Component } from 'react';
import {
View,
StyleSheet,
Navigator,
Text,
TouchableHighlight
} from 'react-native';
import Home from './Home';
import Main from './Main';
class MainApp extends Component {
_navigate(){
this.props.navigator.push({
name: Home
})
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={ () => this._navigate() }>
<Text>GO To View</Text>
</TouchableHighlight>
</View>
);
}
}
and Home component
class Home extends Component {
render() {
return (
<View style={styles.container}>
<Text>Welcome Hello</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default Home;
I still get this error, I am a beginner in react-native so help me please ? why react-native so hard ?
After some hours of work, i resolve my problem
First i create MainApp and i define a Navigator with initialRoute my code look like this
class MainApp extends Component {
renderScene(route, navigator) {
console.log(route, navigator);
if (route.component) {
return React.createElement(route.component, { navigator });
}
}
render() {
return (
<Navigator
initialRoute={{name: 'Home', component: Home}}
configureScene={() => {
return Navigator.SceneConfigs.FloatFromRight;
}}
renderScene={this.renderScene}
/>
);
}
}
and after in Home screen i use this function
_navigate() {
this.props.navigator.replace({
name: 'Main',
component: Main
});
}
So now my project work well , the key is create a screen route hope it useful
So ! First of all, RN is not so hard ^^ I started two weeks ago don't worry it will become easier !
I'll give you an example if you're ok with that !
MainApp
renderScene(route,nav) {
switch (route.screen) {
case "LaunchScreen":
return <LaunchScreen navigator={nav} />
case "LoginScreen":
return <LoginScreen navigator={nav} />
case "ListBillScreen":
return <ListBillScreen navigator={nav} />
case "AddBillScreen":
return <AddBillScreen navigator={nav} />
case "BillScreen":
return <BillScreen navigator={nav} bill={route.props}/>
case "PersistanceDemo":
return <PersistanceDemo navigator={nav} />
}
}
render () {
return (
<Navigator
initialRoute={{screen: 'LaunchScreen'}}
renderScene={(route, nav) => {return this.renderScene(route, nav)}}
/>
)
}
}
You set all your "Routes" in the mainApp okay?
After that, if you want to navigate between views in others .js, you need to do this way :
this.props.navigator.push({ screen: 'AddBillScreen' });
You need to navigate with the name of your screen ! Once you've done that, it will be soooo easy for you to navigate between views you will see !
Keep strong !

Resources