Send data from between components in react native - react-native

I'm writting a simple app have 2 screen:
Login and Main.
In file Login.js:
import React, {Component} from 'react';
import {Text, View, Button, StyleSheet, TextInput} from 'react-native';
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
user_name: '',
password: ''
};
}
render() {
return (
<View>
<Text>Username:</Text>
<TextInput
onChangeText={(text) => {
this.setState({user_name: text});
}}/>
<Text>Password:</Text>
<TextInput
secureTextEntry={true}
onChangeText={(text) => {
this.setState({password: text});
}}/>
<View style={styles.wrapper}>
<Button
onPress={this.props.click}
title="Login"
accessibilityLabel="Login to system"/>
</View>
</View>
);
}
}
Login.propType = {
user: React.PropTypes.string.isRequired,
pass: React.PropTypes.string.isRequired
}
const styles = StyleSheet.create({
wrapper: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around'
}
});
I have Main.js for renderScene when login successfull.
In file index.android.js, I declare class RouteTest for AppRegistry:
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Navigator,
Alert,
Button
} from 'react-native';
import Main from './Screen/Main.js';
import Login from './Screen/Login.js';
class RouteTest extends Component {
renderScene(route, navigator) {
switch (route.name) {
case 'main':
return (<Main />);
case 'login':
return (<Login
click={()=>{
if(this.state.user_name == 'abc' && this.state.password == '123') {
navigator.push({name: 'main'})
} else {
Alert.alert("Login failed");
}
}}/>);
}
}
render() {
return (<Navigator
initialRoute={{
name: 'login'
}}
renderScene={this.renderScene}/>);
}
}
AppRegistry.registerComponent('RouteTest', () => RouteTest);
When I get user_name and password from TextInput of class Login, I using:
this.state.user_name but isn't working.
And my question is: How to get a value of user's input in class Login for class RouteTest.
Thank.

you might want to use react redux. Using this u can acess anything from anywhere fast and simple.
Its a little hard to setup but once u have setup its easy to manage and u get info anywhere in the app refer this link: Getting started with Redux.
It covers different aspects of using redux. Starting off with a simple example of counter. It also deals with how to manage an api call where the result can be accessed anywhere from the app.
UPDATE: A much quicker solution will be to use React Context API. Here is a practical example . If you want a full fledged state management go with redux instead
Good luck!

Try look at https://facebook.github.io/react/docs/refs-and-the-dom.html
Basically you can access the props of Login from your RouteTest using refs set, e.g.
<Login
ref={ref => this._login = ref}
/>
After that you can access the props like this: this._login.xxx

Related

TypeError: Cannot read property 'navigate' of undefined

I wrote a snapshot test for a screen called NewUser.js, here is the test code:
import React from "react";
import NewUser from "../app/screens/NewUser/NewUser"
import renderer from "react-test-renderer"
describe("<NewUser/>", ()=>{
it("snapshot", ()=>{
expect(renderer.create(<NewUser/>).toJSON()).toMatchSnapshot();
});
});
And here is the NewUser.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, Button} from 'react-native';
import styles from './Styles'
export default class NewUser extends Component {
static navigationOptions = () => {
return {
headerStyle: styles.headerStyle,
headerTintColor: '#fff',
headerTitle: 'JetSet',
headerTitleStyle: {
flex: 1,
}
};
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.background}>
<View style={styles.container}>
<Button
onPress={() => navigate('Survey', { survey: 'NewUserQuestions' })}
title="New User"
/>
</View>
</View>
);
}
}
I got the error when I run the test. What should I do to make test runnable? Thanks.
I somehow solved it by doing this
{ navigation } = this.props
...navigation.navigate()
I am still not sure the reason caused that issue, and the solution is not perfect, but it saved my code.

Navigation.getParam is undefined while trying to pass function as parameter

I'm trying to use a function from my Main component in my details component which I user react navigation to navigate to and I want to save some changes in detail screen in my main component
//Main.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity,
KeyboardAvoidingView,
AsyncStorage
} from 'react-native'
import Note from './Note'
import { createStackNavigator, createAppContainer } from "react-navigation";
import Details from './Details';
export default class Main extends React.Component {
static navigationOptions = {
title: 'To do list',
headerStyle: {
backgroundColor: '#f4511e',
},
};
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: ''
};
}
render() {
let notes = this.state.noteArray.map((val,key) => {
return <Note key={key} keyval={key} val={val}
goToDetailPage= {() => this.goToNoteDetail(key)}
/>
});
const { navigation } = this.props;
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details saveEdit={this.saveEdit} />
</View>
);
}
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
selectedTask: this.state.noteArray[key],
saveEdit: this.saveEdit
});
}
saveEdit = (editedTask,dueDate) => {
this.state.noteArray.push({
'creationDate': editedTask['creationDate'],
'taskName': editedTask['taskName'],
'dueDate': dueDate
});
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
}
Then I try to use it as prop in my Detail.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
Button,
TouchableOpacity,
} from 'react-native'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Details extends React.Component {
constructor(props){
super(props);
this.state = {
dueDate = ''
}
}
static navigationOptions = {
headerStyle: {
backgroundColor: '#f4511e',
},
};
componentDidMount = () => {
this.getUserTasks()
}
render() {
const { navigation } = this.props;
const selectedTask = navigation.getParam('selectedTask', 'task');
var { saveEdit} = this.props;
return(
<View key={this.props.keyval} style={styles.container}>
<View style = { styles.info}>
<Text style= {styles.labelStyle}> Due date:
</Text>
<TextInput
onChangeText={(dueData) => this.setState({dueData})}
style={styles.textInput}
placeholder= {selectedTask['dueDate']}
placeholderTextColor='gray'
underlineColorAndroid = 'transparent'
>
</TextInput>
</View>
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)} style={styles.saveButton}>
<Text style={styles.saveButtonText}> save </Text>
</TouchableOpacity>
</View>
);
}
}
I searched a lot to find the solution and I tried many of them but get different undefined errors. This is not what I did in the first place but when I search I found this solution here. And I know it causes lots of issues.
I want to know how can I manage to access to main method from details and pass parameters to it or how can I manage to use main props in my details component
If you are using react-navigation 5, params is no longer under the navigation object but under route object. This is the link to the sample code:
https://reactnavigation.org/docs/params
Solution
<Details saveEdit={this.saveEdit} />
to
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
render() {
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
</View>
);
}
Why?
You are using your Details component in Main screen. So you need to give navigation to Details's props from your Main to use navigation props in Details component.
Because your Details component is not the screen component registered in your navigator(router).
I tried to run your code on my machine but it seems you have too many syntax error in your code (maybe because of copy pasta?)
but it seems you should change
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)}
in Detals.js to
<TouchableOpacity onPress={this.props.navigation.getParams('saveEdit')(selectedTask, this.state.dueDate)}
for clarification this worked for me
in MainPage.js
_test(){
console.log('test');
}
.
.
.
<ActionButton
buttonColor="rgba(231,76,60,1)"
onPress={() => NavigationService.navigate('AddNewSession', {test: this._test})}>
</ActionButton>
and in AddNewSession.js
componentDidMount()
let test = this.props.navigation.getParam('test');
test();
}
There are many mistakes within your codes. First of all you are importing the navigation build-in function {createStackNavigator} in all your files, Main.js and Details.js :
import { createStackNavigator, createAppContainer } from
"react-navigation";
That make me think that you didn't know how the stack navigation or navigation in general functions in react native. You should have a file that handles your routes configuration, let call it MyNavigation.js and then define the routes 'Main' and 'details' in MyNavigations,js. It's only inside MyNavigation.js that you can import "createStackNavigator". Then you will define your functions to move between the screens "Main" and "detail". Those functions will be passed as props to the routes when moving between one another. The overall action wihtin MyNavigation.js will look like:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import Main from './Main';
import Detail from './Detail';
const Stack = createStackNavigator();
function goToDetailFromMainScreen(){
return(this.props.navigation.navigate('switch2'));
}
function DetailSaves(){
return(//your code here to save details);
}
//Here you pass the functions to Main Component to handele Detail componets
's actions
function switch1(){
return(<Main GoToDetails={() => this.goTodetailFromMainScreen()} paramsForDetailActions={() => this.detailSaves()} />)
}
function switch2(){
return(<Details />)
}
export default function MyNavigation() {
return(
<NavigationContainer>
<Stack.Navigator initialRouteName='switch1'>
<Stack.Screen name='switch1' options={{header:()=>null}} component={Main} />
<Stack.Screen name='switch2' options={{headerTitle:"Detail"}} component={Detail} />
</Stack.Navigator>
</NavigationContainer>
)
}
Now inside Main.js you check the props functions passed to it from MyNavigation.js:
// Main.js
constructor(props){
super(props);
}
goToDetails = () => {
this.props.onPress?.();
}
paramsForDetailActions= () => {
this.props.onPress?.();
}

Is there an easy way to create a logout button in the drawer in React Navigation V2?

I want to have logout button in my drawer. The problem is that it should not render a screen, but just straight up log out. Is there a easy way to do it (e.g. somehow modifying the contentOptions' items or onItemPressed property? I couldn't figure something out.
What I'm doing right now is writing a CustomDrawerComponent with a logout button in it, but it's pretty hard to get the styling right and look alike the other DrawerItems.
Here is how I solved this with a custom component. Maybe there is a different way?
import React, { PureComponent } from "react";
import { Image, ScrollView, Text, TouchableOpacity } from "react-native";
import { DrawerItems, SafeAreaView } from "react-navigation";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { clearToken } from "../../api/secureStorage/secureStorage";
import { BUTTON_TEXT_LOGOUT } from "../../config/constants/buttonTexts";
import { logout } from "../../redux/actions/logout/logout";
import styles from "./styles";
export class BurgerMenu extends PureComponent {
static propTypes = {
navigation: PropTypes.object,
logout: PropTypes.func.isRequired
};
logout = () => {
const { navigation, logout } = this.props;
clearToken().then(() => {
logout();
navigation.navigate("LoginScreen");
});
};
render() {
const { logout, ...strippedProps } = this.props; // eslint-disable-line no-unused-vars
return (
<SafeAreaView style={styles.container} forceInset={{ top: "always", horizontal: "never" }}>
<ScrollView>
<DrawerItems {...strippedProps} />
</ScrollView>
<TouchableOpacity style={[styles.footer, styles.item]} onPress={this.logout}>
<Image
source={require("../../assets/icons/exit.png")}
style={styles.icon}
resizeMode="contain"
/>
<Text style={styles.text}>{BUTTON_TEXT_LOGOUT}</Text>
</TouchableOpacity>
</SafeAreaView>
);
}
}
export default connect(
null,
{ logout }
)(BurgerMenu);

Cannot read property 'navigate' of Undefined in React Navigation

i'm React Native newbie. What i'm trying to do is added react navigation to my login page where user can click a button and navigate to the sign up page but i'm getting an error Cannot read property 'navigate' of Undefined. I've already searched the solution over an internet but no luck. This So does not help me - React Navigation - cannot read property 'navigate' of undefined and same with others .
Here is my code
index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Login from './src/screens/Login';
import Signup from './src/screens/Signup';
export default class tapak extends Component {
constructor(props) {
super(props);
this.buttonPress = this.buttonPress.bind(this);
}
render() {
return (
<View style={styles.container}>
<Text style={{color: 'blue'}} onPress={this.buttonPress}>sign up</Text>
</View>
);
}
buttonPress() {
console.log('called');
this.props.navigation.navigate('Signup');
}
}
const Stacks = StackNavigator({
Login: {
screen: Login
},
Signup:{
screen: Signup
}
});
Render the StackNavigator in your index.ios.js and move the button to the Login component:
const Stacks = StackNavigator({
Login: {
screen: Login
},
Signup:{
screen: Signup
}
});
class tapak extends Component {
render() {
return (
<Stacks />
);
}
}
Login.js :
export default class Login extends Component {
constructor(props) {
super(props);
this.buttonPress = this.buttonPress.bind(this);
}
buttonPress() {
console.log('called');
this.props.navigation.navigate('Signup');
}
render() {
return (
<View style={styles.container}>
<Text style={{color: 'blue'}} onPress={this.buttonPress}>sign up</Text>
</View>
);
}
}
Working example
here.
Write this code to index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Login from './src/screens/Login';
import Signup from './src/screens/Signup';
const Stacks = StackNavigator({
Login: {
screen: Login
},
Signup:{
screen: Signup
}
});
Login.js
import React ,{Component} from 'react';
import {
Text, View , Button,Image,
} from 'react-native';
export default class HomeScreen extends Component {
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text
onPress={() => navigate('Signup')}
> SignUp</Text>
</View>
);
}
}
Hope this help you.
I think you need to include navigationOptions, for example:
class MyComponent extends React.Component {
static navigationOptions = {
title: 'Great',
// other configurations
}
render() {
return (
// your view
)
}
}
Also yu need to make sure you use AppRegistry.registerComponent('glfm', () => Stacks); rather than AppRegistry.registerComponent('glfm', () => tapak);
The only answer to this question is to just put const { navigate } = this.props.navigation in your render() function and then you can use it in any component that you need
For Example
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>This is the home screen of the app</Text>
<Button
onPress={() => navigate('Profile', { name: 'Brent' })}
title="Go to Brent's profile"
/>
</View>
);
}
Please read this doc for https://reactnavigation.org/docs/en/navigation-prop.html

Disable console log in react navigation

I'm using react navigation for my app development. When i run log-android, it keeps logging something like this.
Navigation Dispatch: Action: {...}, New State: {...}
which is from createNavigationContainer.js line 150.
I've run through github and document said it could be done by by setting onNavigationStateChange={null} on a top-level navigator.
How can i achieve this by setting onNavigationStateChange={null} and where should i set it?
I've try to set like below, but it the page will not be able to redirect to other page.
export default () => {
<App onNavigationStateChange={null} />
}
Below are my app.js code
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
import { StackNavigator,DrawerNavigator } from 'react-navigation';
import DrawerContent from './components/drawer/drawerContent.js';
import News from './components/news/home.js';
const drawNavigation = DrawerNavigator(
{
Home : {
screen : News ,
navigationOptions : {
header : null
}
}
},
{
contentComponent: props => <DrawerContent {...props} />
}
)
const StackNavigation = StackNavigator({
Home : { screen : drawNavigation,
navigationOptions: {
header: null
}
}
});
export default StackNavigation;
This is my drawerContent.js
import React, {Component} from 'react'
import {View,Text, StyleSheet,
TouchableNativeFeedback,
TouchableOpacity,
TouchableHighlight
} from 'react-native'
import { DrawerItems, DrawerView } from 'react-navigation';
import Icon from 'react-native-vector-icons/Octicons';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
class DrawerContent extends Component {
constructor(props){
super(props);
console.log('DrawerContent|testtttttt');
}
render(){
return (
<View style={styles.container}>
<Text>Hi darren</Text>
<TouchableOpacity style={{ marginBottom:5 }} onPress={() => this.props.navigation.navigate('RegistrationScreen') } >
<View style={styles.nonIconButton}>
<Text style={{ color: 'black',fontSize: 13 }} >Sign Up</Text>
</View>
</TouchableOpacity>
<Text>Hi darren</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default DrawerContent;
First, make sure you are using the latest release of react-navigation as the comment noting that the fix was committed is fairly recent.
Based on your code example, to disable logging for all navigation state changes, you would want to replace this code:
export default StackNavigation;
with:
export default () => (
<StackNavigation onNavigationStateChange={null} />
);
as StackNavigation appears to be your root navigator.
React navigation is great, but this logging is really bad. Solution
const AppNavigator = StackNavigator(SomeAppRouteConfigs);
class App extends React.Component {
render() {
return (
<AppNavigator onNavigationStateChange={null} />
);
}
}