I've been trying some codes for the navigation in react native, I want to navigate from Listlab screen to FormScreen for updating which mean I want to navigate the screen and pass the value to new screen and its textfield. But when I tried, it shown me an error that I already tried to solve it for many times. Can you help me to solve this error, thank you :D
Here's The Error Message:
And Here's my Listlab Code:
import React, { Component } from 'react';
import { View, Text, StyleSheet, Platform, StatusBar} from 'react-native';
import PropTypes from 'prop-types';
import { Card, CardTitle, CardContent, CardAction, CardButton, CardImage } from 'react-native-material-cards'
import { CardItem } from 'native-base';
import { ScrollView } from 'react-native-gesture-handler';
import { createAppContainer } from 'react-navigation';
import {createStackNavigator } from 'react-navigation-stack';
import Button from 'react-native-button';
import { withNavigation } from 'react-navigation';
class ListLab extends Component {
_OnButtonPress(no_pengajuan) {
Alert.alert(no_pengajuan.toString());
}
handleDelete(id){
let url = "http://URL:8000/api/pinjams/"+id ;
// let data = this.state;
fetch(url,{
method:'DELETE',
headers:{
"Content-Type" : "application/json",
"Accept" : "application/json"
},
})
.then((result) => {
result.json().then((resp) => {
console.warn("resp", resp)
alert("Data is Removed")
})
})
}
render() {
this._OnButtonPress = this._OnButtonPress.bind(this);
return (
<View style={styles.pinjamList}>
<StatusBar hidden />
{this.props.pinjams.map((pinjam) => {
return (
<View key={pinjam.id}>
{/* Baru nambah data */}
<Card>
<CardImage
source={{uri: 'http://www.rset.edu.in/pages/uploads/images/computerLab-img1.jpg'}}
title={pinjam.lab }
/>
<CardTitle
title={ pinjam.ketua_kegiatan }
subtitle={ pinjam.keperluan }
/>
<CardContent><Text>{ pinjam.tanggal_mulai} - {pinjam.tanggal_selesai }</Text></CardContent>
<CardContent><Text>{ pinjam.jam_mulai } - {pinjam.jam_selesai }</Text></CardContent>
</Card>
<Button
style={{fontSize:20, color:'red'}}
styleDisabled={{color:'grey'}}
onPress ={()=>{this.handleDelete(pinjam.id)}}
> {"\n"} Delete
</Button>
<Button
style={{fontSize:20, color:'green'}}
styleDisabled={{color:'grey'}}
onPress ={()=>{this.props.navigation.navigate('FormScreen')}}
> {"\n"} Update
</Button>
</View>
)
})}
</View>
);
}
}
const styles = StyleSheet.create({
pinjamList: {
flex: 1,
flexDirection: 'column',
justifyContent: 'space-around',
},
pinjamtext: {
fontSize: 14,
fontWeight: 'bold',
textAlign: 'center',
}
});
export default withNavigation(ListLab);
And This one is my FormScreen Code:
import React , { Component } from 'react';
import {
ScrollView,
View,
Text,
StyleSheet,
StatusBar
} from 'react-native';
import { Header, Left, Right, Icon, Footer, Label} from 'native-base';
import Button from 'react-native-button';
import t from 'tcomb-form-native';
import { Dropdown } from 'react-native-material-dropdown';
import { TextField } from 'react-native-material-textfield';
import DatePicker from 'react-native-datepicker';
import moment from 'moment';
class FormScreens extends Component {
static navigationOptions = {
drawerIcon : ({tintColor})=>(
<Icon name="paper" style={{ fontSize: 24, color: tintColor }}/>
)
}
constructor(){
super();
this.state = {
ketua_kegiatan: '',
lab: '',
level: '',
tanggal_mulai: '',
tanggal_selesai: '',
jam_mulai: '',
jam_selesai: '',
daftar_nama: '',
keperluan: '',
kontak_ketua:'',
dosen_pembina: '',
app_laboran: '',
app_kalab: '',
app_kajur: '',
app_pudir: '',
}
}
submit(id){
let url = "http://URL:8000/api/pinjams"+id;
let data = this.state;
fetch(url,{
method:'PUT',
headers:{
"Content-Type" : "application/json",
"Accept" : "application/json"
},
body: JSON.stringify(data)
})
.then((result) => {
result.json().then((resp) => {
console.warn("resp", resp)
alert("Data is Updated")
})
})
}
render() {
let lab = [{
value: '313',
}, {
value: '316',
}, {
value: '317',
}, {
value: '318',
}, {
value: '319',
}, {
value: '320',
}, {
value: '324',
}, {
value: '325',
}, {
value: '329',
}, {
value: '330',
}, {
value: '234',
}, {
value: '283',
}, {
value: '218',
}, {
value: '224',
}, {
value: '225',
}, {
value: '230',
}, {
value: '233',
}, {
value: '135',
}, {
value: '136',
}, {
value: '137',
}, {
value: 'Workshop',
}, {
value: 'Lab Bahasa',
}];
let level = [{
value: 1,
}, {
value: 2,
}, {
value: 3,
}];
return (
//08-08-2019 (Ubah view menjadi ScrollView)
<ScrollView style={styles.container}>
<StatusBar hidden />
<Header style={{backgroundColor:'orange', flex:0.8}}>
<Left style={{justifyContent:"flex-start",flex:1,marginTop:5}}>
<Icon name="menu" onPress={()=>this.props.navigation.openDrawer()} />
</Left>
</Header>
<View style={{padding:20}}>
<Text style={{fontSize:20,textAlign: 'center',paddingLeft:20,fontWeight: 'bold'}}>{"\n"}Halaman Pengajuan</Text>
<TextField
label = 'ketua_kegiatan'
// value = {ketua_kegiatan}
onChangeText={ (ketua_kegiatan) => this.setState({ ketua_kegiatan }) }
// onChange={(data) => { this.setState({ketua_kegiatan:data.target.value}) }}
value = {this.state.ketua_kegiatan}
/>
<Dropdown
label='Laboratorium'
data={lab}
onChangeText={ (lab) => this.setState({ lab }) }
/>
<Dropdown
label='Level'
data={level}
onChangeText={ (level) => this.setState({ level }) }
/>
<TextField
label = 'Tanggal Mulai'
// value = {tanggal_mulai}
onChangeText={ (tanggal_mulai) => this.setState({ tanggal_mulai }) }
// onChange={(data) => { this.setState({tanggal_mulai:data.target.value}) }}
value = {this.state.tanggal_mulai}
/>
<TextField
label = 'Tanggal Selesai'
// value = {tanggal_selesai}
onChangeText={ (tanggal_selesai) => this.setState({ tanggal_selesai }) }
// onChange={(data) => { this.setState({tanggal_selesai:data.target.value}) }}
value = {this.state.tanggal_selesai}
/>
<TextField
label = 'Jam Mulai'
// value = {jam_mulai}
onChangeText={ (jam_mulai) => this.setState({ jam_mulai }) }
// onChange={(data) => { this.setState({jam_mulai:data.target.value}) }}
value = {this.state.jam_mulai}
/>
<TextField
label = 'Jam Selesai'
// value = {jam_selesai}
onChangeText={ (jam_selesai) => this.setState({ jam_selesai }) }
// onChange={(data) => { this.setState({jam_selesai:data.target.value}) }}
value = {this.state.jam_selesai}
/>
<TextField
label = 'Keperluan'
// value = {keperluan}
onChangeText={ (keperluan) => this.setState({ keperluan }) }
// onChange={(data) => { this.setState({keperluan:data.target.value}) }}
value = {this.state.keperluan}
/>
<TextField
label = 'Daftar Nama'
// value = {daftar_nama}
onChangeText={ (daftar_nama) => this.setState({ daftar_nama }) }
// onChange={(data) => { this.setState({daftar_nama:data.target.value}) }}
value = {this.state.daftar_nama}
/>
<TextField
label = 'kontak_ketua'
// value = {kontak_ketua}
onChangeText={ (kontak_ketua) => this.setState({ kontak_ketua }) }
// onChange={(data) => { this.setState({kontak_ketua:data.target.value}) }}
value = {this.state.kontak_ketua}
/>
<TextField
label = 'Dosen Pembina'
// value = {dosen_pembina}
onChangeText={ (dosen_pembina) => this.setState({ dosen_pembina }) }
// onChange={(data) => { this.setState({dosen_pembina:data.target.value}) }}
value = {this.state.dosen_pembina}
/>
<TextField
label = 'app_laboran'
// value = {app_laboran}
onChangeText={ (app_laboran) => this.setState({ app_laboran }) }
// onChange={(data) => { this.setState({app_laboran:data.target.value}) }}
value = {this.state.app_laboran}
/>
<Button
style={{fontSize:20, color:'orange'}}
styleDisabled={{color:'grey'}}
onPress ={()=>{this.submit(pinjam.id)}}
> {"\n"} Submit
</Button>
</View>
{/* <Form type={Pengajuan}/> */}
<Footer style={{backgroundColor:'white'}}>
<Text style={{paddingTop:10,color:'grey'}}>{"\n"}Copyright reserved to #Leony_vw</Text>
</Footer>
</ScrollView>
);
}
}
export default FormScreens;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
// ...Platform.select({
// android: {
// marginTop: StatusBar.currentHeight
// }
// })
},
});
Here's my App.js:
import React from 'react';
import { StyleSheet, Text, View, SafeAreaView,ScrollView, Dimensions, Image } from 'react-native';
import { createDrawerNavigator, DrawerItems, createAppContainer } from 'react-navigation';
// import HomeScreen from './screens/HomeScreen';
// import FormScreen from './screens/FormScreen';
// import SigninScreen from './screens/SigninScreen';
import HomeScreen from './screens/laboran/HomeScreen';
import FormScreen from './screens/laboran/FormScreen';
import * as firebase from "firebase";
const { width } = Dimensions.get('window');
var firebaseConfig = {
apiKey: "XXXXXX",
authDomain: "XXXXX",
databaseURL: "XXXXX",
projectId: "XXXXX",
storageBucket: "XXXXX",
messagingSenderId: "XXXXX",
appId: "XXXXX"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
export default class App extends React.Component{
render() {
return (
<Apps/>
);
}
}
const CustomDrawerComponent = (props) => (
<SafeAreaView style={{ flex:1 }}>
<View style={{height:150, backgroundColor: 'white', alignItems :'center', justifyContent:'center'}}>
<Image source={require('./assets/up2.png')} style={{height:50, width:50,borderRadius:35 }}/>
</View>
<ScrollView>
<DrawerItems {...props}/>
</ScrollView>
</SafeAreaView>
)
const AppDrawerNavigator = createDrawerNavigator({
// Login:SigninScreen,
Home:HomeScreen,
Form:FormScreen
}, {
contentComponent: CustomDrawerComponent,
drawerWidth: width,
contentOptions:{
activeTintColor:'orange'
}
})
const Apps = createAppContainer(AppDrawerNavigator)
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
That is probably because Listlab is rendered by a component that is actually a screen.
For example, let say your FormScreen would render the Listlab component. FormScreen has access to the navigation prop, but Listlab does not.
You have 2 solutions:
- pass the navigation prop to Listlab
- use the withNavigation HOC
I found the solution last night, I think I can's just navigate from ListLab because ListLab is just like a child screen of HomeScreen. When I try it on HomeScreen, the prop is doing fine, and it can navigate to my FormScreen tho. And also, I think I did call the wrong alias of FormScreen in App.js and that's the problem as well. But now, I would like to put the button and the navigation in ListLab, I still wonder how can I navigate using button in child screen. But thanks guys for helping me :D Cheers!
Related
I'm trying to import a component into my App.js class but when I try I get the error in my android emulator
invariant violation element type is invalid: expected a string or a class/function but got undefined you likely forgot to export your component from the file its defined in, or you might have mixed up default and named imports
check the render method of 'login'
my problem is that I checked that i'm importing a default import of the login component in my App.js and I am exporting the Login component correctly from what I can tell:
import React, {Component} from 'react';
import {StyleSheet,ScrollView,View,Text,Input,Button,SecureTextEntry,ActivityIndicator} from 'react-native';
import * as firebase from 'firebase';
import auth from '#react-native-firebase/auth';
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
export default class Login extends Component {
state={
email: '',
password: '',
authenticating: false
};
componentDidMount(){
const firebaseConfig = {
apiKey: 'garbagekey',
authDomain: 'garbage auth domain'
}
firebase.initializeApp(firebaseConfig)
}
onButtonPress = () =>{
console.log("button pressed")
this.setState({authenticating:true})
}
contentBoolRender = () =>{
if(this.state.authenticating===true){
return(
<View>
<ActivityIndicator size="large"/>
</View>
)
}
return(
<View>
<Input
placeholder="Enter your Email..."
label = "Email"
onChangeText = {email => this.setState({email})}
value = {this.state.email}
/>
<Input
placeholder="Enter your Password..."
label = "Password"
onChangeText = {password => this.setState({password})}
value = {this.state.password}
SecureTextEntry
/>
<Button title="login" onpress={()=>this.onButtonPress()}></Button>
</View>
)
}
render() {
return(
<View>
{this.contentBoolRender()}
</View>
);
}
}
const styles = StyleSheet.create({
login:{
padding: 20,
backgroundColor: 'white'
},
});
App.js
import React, {Component} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
Button,
} from 'react-native';
import * as firebase from 'firebase';
import auth from '#react-native-firebase/auth';
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import Notes from "./notes.js";
import CreateNote from "./createnote.js";
import Login from "./login.js";
class App extends Component {
state = {
loggedin: false,
notes: [
{
id: 1,
text: "mow the lawn",
author: "dean",
time: "10am"
},
{
id: 2,
text: "feed the dog",
author: "sam",
time: "2pm"
}
]
};
componentDidMount(){
const firebaseConfig = {
apiKey: 'AIzaSyABmRXh2nlBt4FtjfOWNaoz7q5Wy5pGFlc',
authDomain: 'familytodo-28018.firebaseapp.com'
}
firebase.initializeApp(firebaseConfig)
}
confirmLogin=()=>{
this.setState({loggedin:true})
}
updateNotes = (title, name, eventTime) => {
console.log("making new note");
let newNote = {
text: title,
author: name,
time: eventTime
};
this.setState(state => {
const list = state.notes.concat(newNote);
console.log(list);
return {
notes: list
};
});
};
deleteNotes = note => {
console.log("note deleted", note.id);
this.setState(state => {
var list = this.state.notes;
for (let i = 0; i < this.state.notes.length; i++) {
if (this.state.notes[i].id === note.id) {
list.pop(i);
}
}
return {
notes: list
};
});
};
conditionalRender=()=>{
if(this.state.loggedin===false){
return (
<View>
<Login confirmlogin = {this.confirmLogin} />
</View>
)
}
return(
<View>
<CreateNote
handleName={this.handleName}
handleEvent={this.handleEvent}
handleTime={this.handleTime}
updateNotes={this.updateNotes}
/>
<Notes style={styles.notes} notes={this.state.notes} deleteNotes={this.deleteNotes} />
</View>
);
}
render() {
return(
<View>
{this.conditionalRender()}
</View>
);
}
}
const styles = StyleSheet.create({
app: {
marginHorizontal: "auto",
maxWidth: 500
},
logo: {
height: 80
},
header: {
padding: 20
},
title: {
fontWeight: "bold",
fontSize: 15,
marginVertical: 10,
textAlign: "center"
},
notes:{
marginHorizontal: '50%'
},
text: {
lineHeight: 15,
fontSize: 11,
marginVertical: 11,
textAlign: "center"
},
link: {
color: "#1B95E0"
},
code: {
fontFamily: "monospace, monospace"
}
});
export default App;
any help would be appreciate greatly please help me provide better info if possible :)
I think this is happening because react-native has no exported member named Input. I think you are looking for either TextInput (from react-native) or Input (from react-native-elements which has a label prop)
For the TextInput, try changing the login component to this:
import React, {Component} from 'react';
import {ActivityIndicator, Button, TextInput, View} from 'react-native';
import * as firebase from 'firebase';
export default class Login extends Component {
state = {
email: '',
password: '',
authenticating: false
};
componentDidMount() {
const firebaseConfig = {
apiKey: 'garbagekey',
authDomain: 'garbage auth domain'
};
firebase.initializeApp(firebaseConfig);
}
onButtonPress = () => {
console.log("button pressed");
this.setState({authenticating: true});
};
contentBoolRender = () => {
if (this.state.authenticating === true) {
return (
<View>
<ActivityIndicator size="large"/>
</View>
);
}
return (
<View>
<TextInput
placeholder="Enter your Email..."
onChangeText={email => this.setState({email})}
value={this.state.email}
/>
<TextInput
placeholder="Enter your Password..."
onChangeText={password => this.setState({password})}
value={this.state.password}
secureTextEntry
/>
<Button title="login" onPress={() => this.onButtonPress()}/>
</View>
);
};
render() {
return (
<View>
{this.contentBoolRender()}
</View>
);
}
}
or for Input try using this:
import React, {Component} from 'react';
import {ActivityIndicator, Button, View} from 'react-native';
import { Input } from 'react-native-elements';
import * as firebase from 'firebase';
export default class Login extends Component {
state = {
email: '',
password: '',
authenticating: false
};
componentDidMount() {
const firebaseConfig = {
apiKey: 'garbagekey',
authDomain: 'garbage auth domain'
};
firebase.initializeApp(firebaseConfig);
}
onButtonPress = () => {
console.log("button pressed");
this.setState({authenticating: true});
};
contentBoolRender = () => {
if (this.state.authenticating === true) {
return (
<View>
<ActivityIndicator size="large"/>
</View>
);
}
return (
<View>
<Input
placeholder="Enter your Email..."
label = "Email"
onChangeText={email => this.setState({email})}
value={this.state.email}
/>
<Input
placeholder="Enter your Password..."
label = "Password"
onChangeText={password => this.setState({password})}
value={this.state.password}
secureTextEntry
/>
<Button title="login" onPress={() => this.onButtonPress()}/>
</View>
);
};
render() {
return (
<View>
{this.contentBoolRender()}
</View>
);
}
}
Additionally, have a look through the code above as your Login component had a few other typos including: secureTextEntry and onPress
I am new to react native. I am doing a simple app where I add name and age of a person to firebase and then showing it in the list, I am using flatList in this project but it asks to import all the attributes of the flatList. if I add only 2 attributes like data, renderItem it gives an error, please help
here my code
import React from "react";
import {StyleSheet, View, Button, Text, FlatList, TextInput, ListView} from "react-native";
import firebase from './firebase'
let db = firebase.firestore();
class TextInputExample extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
userName: '',
userAge: '',
input1Background: 'red',
textColor1: 'white',
input2Background: 'red',
textColor2: 'white'
};
}
componentDidMount(): void {
db.collection('users')
.onSnapshot((snapshot) => {
snapshot.docChanges().forEach(change => {
if (change.type === 'added') {
this.state.data.push({
name: change.doc.get('name'),
age: change.doc.get('age')
});
console.log(this.state.data);
}
})
}, (error => {
console.log(error.message);
}))
}
addToDatabase = () => {
let data = {
name: this.state.userName,
age: this.state.userAge
};
console.log(data);
db.collection('users').add(data)
.then(ref => {
}).catch(msg => {
console.log(msg);
});
};
renderItem = ({item}) => {
return(
<View>
<Text>{item.name}</Text>
<Text>{item.age}</Text>
</View>
);
};
render(): React.Node {
return (
<View style={styles.container}>
<TextInput
placeHolder={'Enter name'}
onChangeText={(text) => this.setState( {userName: text} )}
/>
<TextInput
placeHolder={'Enter Age'}
onChangeText={(text) => this.setState( {userAge: text} )}
/>
<Button title={'Add'} onPress={() => this.addToDatabase()}/>
<View>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
/>
</View>
</View>
);
}
}
export default TextInputExample;
const styles = StyleSheet.create({
container: {
flex: 1, alignSelf: 'center', alignItems: 'center'
}
});
I think your error is because you're updating your state in the wrong way, if you want to add an element to an array in your state you must do it using the setState method and not directly accessing to the array and push it.
Do this
const newItem = {
name: change.doc.get('name'),
age: change.doc.get('age')
}
this.setState((prevState) => ({
...prevState,
data: [...prevState, newItem]
}))
I'm currently developing an app using react native, right now my issue is that i couldn't navigate to main screen after login. Below is my code.
This is App.js (EDITED)
import React from 'react';
import { Loading } from './components/common/';
import TabNavigator from './screens/TabNavigator';
import AuthNavigator from './screens/AuthNavigator';
import MainNavigator from './screens/MainNavigator';
import deviceStorage from './services/deviceStorage.js';
import { View, StyleSheet } from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {
token: '',
loading: true
}
this.newJWT = this.newJWT.bind(this);
this.deleteJWT = deviceStorage.deleteJWT.bind(this);
this.loadJWT = deviceStorage.loadJWT.bind(this);
this.loadJWT();
}
state = {
isLoadingComplete: false,
};
newJWT(token){
this.setState({
token: token
});
}
render() {
if (this.state.loading) {
return (
<Loading size={'large'} />
);
} else if (!this.state.token) {
return (
<View style={styles.container}>
<AuthNavigator screenProps = {{setToken:this.newJWT}} />
</View>
);
} else if (this.state.token) {
return (
<View style={styles.container}>
<MainNavigator screenProps = {{token: this.state.token,
deleteJWT:this.deleteJWT,}} />
</View>
);
}
}
}
This is Login.js (EDITED-v2)
import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView,
TouchableOpacity, TextInput, Alert } from 'react-native';
import axios from 'axios';
import deviceStorage from '../services/deviceStorage';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
error: '',
loading: false
};
this.loginUser = this.loginUser.bind(this);
this.onLoginFail = this.onLoginFail.bind(this);
}
loginUser() {
const { username, password, password_confirmation } = this.state;
this.setState({ error: '', loading: true });
// NOTE Post to HTTPS only in production
axios.post("http://192.168.1.201:8000/api/login",{
username: username,
password: password
})
.then((response) => {
console.log('response',response)
deviceStorage.saveKey("token", response.data.token);
console.log(response.data.token);
this.props.newJWT(response.data.token);
})
.catch((error) => {
const status = error.response.status
if (status === 401) {
this.setState({ error: 'username or password not recognised.' });
}
this.onLoginFail();
//console.log(error);
//this.onLoginFail();
});
}
onLoginFail() {
this.setState({
error: 'Login Failed',
loading: false
});
}
render() {
// other codes here
}
const styles = StyleSheet.create({
// other codes here
});
export { Login };
This is TabNavigator.js (Added)
import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import Profile from '../screens/Profile';
const TabNavigator = createMaterialTopTabNavigator(
{
Profile: {
screen: props => <Profile {...props.screenProps} />,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused
icon
size={30}
style={{ color: tintColor }}
/>
),
}
},
},
{ initialRouteName: 'Profile',
tabBarPosition: 'top',
swipeEnabled: false,
animationEnabled: true,
lazy: true,
tabBarOptions: {
showLabel: false,
showIcon: true,
activeTintColor: 'orange',
inactiveTintColor: 'orange',
style: {
backgroundColor: '#555',
},
indicatorStyle: {
color: '#orange'
}
}
}
);
const screenTitles = {
Profile: { title: 'Profiler' },
Home: { title: 'Home' },
};
TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = screenTitles[routeName].title;
const tabBarVisible = false;
return {
headerTitle,
tabBarVisible
};
};
export default TabNavigator;
This is my AuthLoadingScreen.js
import React from 'react';
import { View } from 'react-native';
import { Login } from '../screens/Login';
class AuthLoadingScreen extends React.Component {
constructor(props){
super(props);
this.state = {
showLogin: true
};
this.whichForm = this.whichForm.bind(this);
this.authSwitch = this.authSwitch.bind(this);
}
authSwitch() {
this.setState({
showLogin: !this.state.showLogin
});
}
whichForm() {
if(this.state.showLogin){
return(
<Login newJWT={this.props.newJWT} authSwitch={this.authSwitch} />
);
} else {
}
}
render() {
return(
<View style={styles.container}>
{this.whichForm()}
</View>
);
}
}
export default AuthLoadingScreen;
const styles = {
// style codes here
};
Lastly, this is my Profile.js
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, Alert, Platform } from
'react-native';
import { Button, Loading } from '../components/common/';
import axios from 'axios';
export default class Profile extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
email: '',
name: '',
error: ''
}
}
componentDidMount(){
this.onLocationPressed();
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.props.token
};
axios({
method: 'GET',
url: 'http://192.168.1.201:8000/api/user',
headers: headers,
}).then((response) => {
console.log('response',response)
console.log('response2',this.props.token)
this.setState({
email: response.data.user.email,
name: response.data.user.name,
loading: false
});
}).catch((error) => {
console.log(error);
this.setState({
error: 'Error retrieving data',
loading: false
});
});
}
render() {
const { container, emailText, errorText } = styles;
const { loading, email, name, error } = this.state;
if (loading){
return(
<View style={container}>
<Loading size={'large'} />
</View>
)
} else {
return(
<View style={container}>
<View>
<Text style={emailText}>Your email: {email}</Text>
<Text style={emailText}>Your name: {name}</Text>
</View>
<Button onPress={this.props.deleteJWT}>
Log Out
</Button>
</View>
);
}
}
}
const styles = {
// style codes here
};
I've fixed the previous problem that couldn't start the app. Right now i can see the login screen, but when i pressed login, there's a yellow box that indicates some problem. I've included the screenshot below.
Lastly i've added the deviceStorage.js
deviceStorage.js
import { AsyncStorage } from 'react-native';
const deviceStorage = {
async saveKey(key, valueToSave) {
try {
await AsyncStorage.setItem(key, valueToSave);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async loadJWT() {
try {
const value = await AsyncStorage.getItem('token');
if (value !== null) {
this.setState({
token: value,
loading: false
});
} else {
this.setState({
loading: false
});
}
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async deleteJWT() {
try{
await AsyncStorage.removeItem('token')
.then(
() => {
this.setState({
token: ''
})
}
);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
}
};
export default deviceStorage;
Before navigate
After navigate
This is my setup. It works like a charm. Sorry if it's a bit messy. I removed some stuff for clarity and I may have missed something:
App.js
import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { Asset, Font, Icon } from 'expo';
import { ENDPOINT, USER_TYPE } from './src/config'
import { Loading } from './src/components/common/';
import deviceStorage from './src/services/deviceStorage.js';
import TabNavigator from './src/TabNavigator';
import AuthNavigator from './src/AuthNavigator';
import MainNavigator from './src/MainNavigator';
import globalStyles from './src/globalStyles';
import './ReactotronConfig';
export default class App extends React.Component {
constructor() {
super();
this.state = {
jwt: '',
loading: true,
};
this.newJWT = this.newJWT.bind(this);
this.deleteJWT = deviceStorage.deleteJWT.bind(this);
this.loadJWT = deviceStorage.loadJWT.bind(this);
this.loadJWT();
}
state = {
isLoadingComplete: false,
};
newJWT(jwt) {
this.setState({
jwt: jwt
});
}
render() {
if (this.state.loading) {
return (
<Loading size={'large'} />
);
} else if (!this.state.jwt) {
//console.log(this.props, '<=== app.js');
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AuthNavigator screenProps={{setToken: this.newJWT }} />
</View>
);
} else {
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<MainNavigator
screenProps={{ jwt: this.state.jwt,
deleteToken: this.deleteJWT,
}}
/>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'center',
},
});
AuthNavigator.js
import React from 'react';
import { createAppContainer, createBottomTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import AuthScreen from './screens/AuthScreen';
const AuthNavigator = createBottomTabNavigator(
{
Auth: (props) => {
return <AuthScreen {...props.screenProps} />;
}
},
{ initialRouteName: 'Auth',
tabBarOptions: {
showLabel: false,
activeBackgroundColor: '#eee',
}
}
);
export default createAppContainer(AuthNavigator);
MainNavigator.js
import React from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import TabNavigator from './TabNavigator';
const MainNavigator = createStackNavigator({
Main: TabNavigator },
{
initialRouteName: 'Main',
defaultNavigationOptions: {
headerTitleStyle: {
fontSize: 20,
textTransform: 'uppercase'
}
}
});
export default createAppContainer(MainNavigator);
TabNavigator.js
import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import IconBadge from 'react-native-icon-badge';
import ProfileScreen from './screens/ProfileScreen';
import NotificationsScreen from './screens/NotificationsScreen';
import HomeStackNavigator from './HomeStackNavigator';
import CartStackNavigator from './CartStackNavigator';
import QuotesStackNavigator from './QuotesStackNavigator';
import InitialRoute from './InitialRoute';
const TabNavigator = createMaterialTopTabNavigator(
{
Profile: {
screen: props => <ProfileScreen {...props.screenProps} />,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused icon
size={30}
style={{ color: tintColor }}
/>
),
}
},
Home: HomeStackNavigator,
Quotes: QuotesStackNavigator,
Notifications: { screen: props => <NotificationsScreen {...props.screenProps} />,
navigationOptions: ({ screenProps }) => ({
tabBarIcon: ({ tintColor, focused }) => (
<IconBadge
MainElement={
<Ionicons
name={focused ? 'ios-notifications' : 'ios-notifications'}
size={30}
style={{ color: tintColor }}
/>
}
BadgeElement={
<Text style={{ color: '#FFFFFF' }}>{screenProps.unreadMessagesCount}</Text>
}
IconBadgeStyle={{ width: 15,
height: 15,
position: 'absolute',
top: 1,
left: -6,
marginLeft: 15,
backgroundColor: 'red' }}
Hidden={screenProps.unreadMessagesCount === 0}
/>
)
})
},
Cart: CartStackNavigator,
},
{ initialRouteName: 'Profile',
tabBarPosition: 'top',
swipeEnabled: false,
animationEnabled: true,
lazy: true,
tabBarOptions: {
showLabel: false,
showIcon: true,
activeTintColor: 'orange',
inactiveTintColor: 'orange',
style: {
backgroundColor: '#555',
},
indicatorStyle: {
color: '#orange'
}
}
}
);
const screenTitles = {
Profile: { title: 'Hola Maestro' },
Home: { title: 'Selecciona la Categoría' },
Quotes: { title: 'Mi Historial de Cotizaciones' },
Notifications: { title: 'Notificaciones' },
Cart: { title: 'Mi Pedido' },
};
TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = screenTitles[routeName].title;
const tabBarVisible = false;
return {
headerTitle,
tabBarVisible
};
};
export default TabNavigator;
Login.js
import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView } from 'react-native';
import axios from 'axios';
import Ionicons from 'react-native-vector-icons/Ionicons';
//import Pusher from 'pusher-js/react-native';
import { ENDPOINT, USER_TYPE } from '../config'
import deviceStorage from '../services/deviceStorage';
import { Input, TextLink, Loading, Button } from './common';
import Header from '../components/Header';
class Login extends Component {
constructor(props){
super(props);
this.state = {
username: '',
password: '',
error: '',
loading: false
};
this.pusher = null; // variable for storing the Pusher reference
this.my_channel = null; // variable for storing the channel assigned to this user
this.loginUser = this.loginUser.bind(this);
}
loginUser() {
const { username, password, password_confirmation } = this.state;
axios.post(`${ENDPOINT}/login`, {
user: {
login: username,
password: password
}
})
.then((response) => {
deviceStorage.saveKey("id_token", response.headers.authorization);
this.props.newJWT(response.headers.authorization);
//this.setPusherData();
})
.catch((error) => {
this.onLoginFail();
});
}
onLoginFail() {
this.setState({
error: 'Usuario o contraseña incorrecta',
loading: false
});
}
}
render() {
const { username, password, error, loading } = this.state;
const { container, form, section, errorTextStyle, iconContainer, inputContainer, titleText } = styles;
return (
<View style={container}>
<Header title="¡Bienvenido Amigo Maestro!" />
<View style={form}>
<ImageBackground source={require('./cemento-login.jpg')} style={{ flex: 1, marginBottom: 30 }}>
<View style={{marginTop: 120}}>
<Text style={titleText}>INICIAR SESIÓN</Text>
<View style={section}>
<View style={iconContainer}>
<Ionicons
name={'ios-person'}
size={26}
style={{ color: '#fff', alignSelf: 'center' }}
/>
</View>
<View style={inputContainer}>
<Input
placeholder="Usuario"
value={username}
onChangeText={username => this.setState({ username })}
/>
</View>
</View>
<View style={section}>
<View style={iconContainer}>
<Ionicons
name={'ios-lock'}
size={26}
style={{ color: '#fff', alignSelf: 'center' }}
/>
</View>
<View style={inputContainer}>
<Input
secureTextEntry
placeholder="Contraseña"
value={password}
onChangeText={password => this.setState({ password })}
/>
</View>
</View>
</View>
</ImageBackground>
</View>
<KeyboardAvoidingView
behavior="padding"
keyboardVerticalOffset={30}
>
<TextLink style={{ }} onPress={this.props.formSwitch}>
Aún no estas registrado? Regístrate
</TextLink>
<TextLink style={{ }} onPress={this.props.forgotPassword}>
Olvidaste tu contraseña?
</TextLink>
<Text style={errorTextStyle}>
{error}
</Text>
{!loading ?
<Button onPress={this.loginUser}>
Ingresar
</Button>
:
<Loading size={'large'} />}
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
form: {
flex: 0.8
},
section: {
flexDirection: 'row',
backgroundColor: '#eee',
borderRadius: 3,
marginTop: 10,
height: 40,
marginLeft: '10%',
marginRight: '10%',
},
titleText: {
color: '#fff',
alignSelf: 'center',
fontSize: 20,
marginBottom: 10
},
errorTextStyle: {
alignSelf: 'center',
fontSize: 18,
color: 'red'
},
iconContainer: {
flex: 0.1,
height: 40,
borderRadius: 3,
alignSelf: 'center',
justifyContent: 'center',
backgroundColor: 'orange',
},
inputContainer: {
flex: 0.8,
alignSelf: 'flex-start',
marginLeft: -70,
}
});
export { Login };
Inside App.js you never change loading to false so the render method never gets to any of the other conditions. Once you have received the token you need to update state and change loading.
I create a component Confirm.js with react-native <Modal /> that has two DropDownMenu and two <Button />.
I want user click the Yes <Button /> than i can get the DropDownMenu onOptionSelected value. I think i should use this.props but i have no idea how to do it.
I want get the value in MainActivity.js from Confirm.js
Any suggestion would be appreciated. Thanks in advance.
Here is my MainActivty.js click the <Button /> show <Confirm />:
import React, { Component } from 'react';
import { Confirm } from './common';
import { Button } from 'react-native-elements';
class MainActivity extends Component {
constructor(props) {
super(props);
this.state = { movies: [], content: 0, showModal: false, isReady: false };
}
// close the Confirm
onDecline() {
this.setState({ showModal: false });
}
render() {
return (
<View style={{ flex: 1 }}>
<Button
onPress={() => this.setState({ showModal: !this.state.showModal })}
backgroundColor={'#81A3A7'}
containerViewStyle={{ width: '100%', marginLeft: 0 }}
icon={{ name: 'search', type: 'font-awesome' }}
title='Open the confirm'
/>
<Confirm
visible={this.state.showModal}
onDecline={this.onDecline.bind(this)}
>
</Confirm>
</View>
);
}
}
export default MainActivity;
Confirm.js:
import React from 'react';
import { Text, View, Modal } from 'react-native';
import { DropDownMenu } from '#shoutem/ui';
import TestConfirm from './TestConfirm';
import { CardSection } from './CardSection';
import { Button } from './Button';
import { ConfirmButton } from './ConfirmButton';
const Confirm = ({ children, visible, onAccept, onDecline }) => {
const { containerStyle, textStyle, cardSectionStyle } = styles;
return (
<Modal
visible={visible}
transparent
animationType="slide"
onRequestClose={() => {}}
>
<View style={containerStyle}>
<CardSection style={cardSectionStyle}>
{/* Here is my DropDownMenu */}
<TestConfirm />
</CardSection>
<CardSection>
<ConfirmButton onPress={onAccept}>Yes</ConfirmButton>
<ConfirmButton onPress={onDecline}>No</ConfirmButton>
</CardSection>
</View>
</Modal>
);
};
const styles = {
cardSectionStyle: {
justifyContent: 'center'
},
textStyle: {
flex: 1,
fontSize: 18,
textAlign: 'center',
lineHeight: 40
},
containerStyle: {
backgroundColor: 'rgba(0, 0, 0, 0.75)',
position: 'relative',
flex: 1,
justifyContent: 'center'
},
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
}
};
export { Confirm };
TestConfirm.js
import React, { Component } from 'react';
import { View } from 'react-native';
import { DropDownMenu, Title, Image, Text, Screen, NavigationBar } from '#shoutem/ui';
import {
northCities,
centralCities,
southCities,
eastCities,
islandCities
} from './CityArray';
class TestConfirm extends Component {
constructor(props) {
super(props);
this.state = {
zone: [
{
id: 0,
brand: "North",
children: northCities
},
{
id: 1,
brand: "Central",
children: centralCities
},
{
id: 2,
brand: "South",
children: southCities
},
{
id: 3,
brand: "East",
children: eastCities
},
{
id: 4,
brand: "Island",
children: islandCities
},
],
}
}
render() {
const { zone, selectedZone, selectedCity } = this.state
return (
<Screen>
<DropDownMenu
style={{
selectedOption: {
marginBottom: -5
}
}}
styleName="horizontal"
options={zone}
selectedOption={selectedZone || zone[0]}
onOptionSelected={(zone) =>
this.setState({ selectedZone: zone, selectedCity: zone.children[0] })}
titleProperty="brand"
valueProperty="cars.model"
/>
<DropDownMenu
style={{
selectedOption: {
marginBottom: -5
}
}}
styleName="horizontal"
options={selectedZone ? selectedZone.children : zone[0].children} // check if zone selected or set the defaul zone children
selectedOption={selectedCity || zone[0].children[0]} // set the selected city or default zone city children
onOptionSelected={(city) => this.setState({ selectedCity: city })} // set the city on change
titleProperty="cnCity"
valueProperty="cars.model"
/>
</Screen>
);
}
}
export default TestConfirm;
If i console.log DropDownMenu onOptionSelected value like the city it would be
{cnCity: "宜蘭", enCity: "Ilan", id: 6}
I want to get the enCity from MainActivity.js
ConfirmButton.js:
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const ConfirmButton = ({ onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
);
};
const styles = {
{ ... }
};
export { ConfirmButton };
You can pass a function to related component via props and run that function with the required argument you got from the dropdowns. Because you have couple of components in a tree it is going to be a little hard to follow but if you get the idea I'm sure you'll make it simpler. Also after getting comfortable with this sort of behavior and react style coding you can upgrade your project to some sort of global state management like redux, flux or mobx.
Sample (removed unrelated parts)
class MainActivity extends Component {
onChangeValues = (values) => {
// do some stuf with the values
// value going to have 2 properties
// { type: string, value: object }
const { type, value } = values;
if(type === 'zone') {
// do something with the zone object
} else if(type === 'city') {
// do something with the city object
}
}
render() {
return(
<Confirm onChangeValues={this.onChangeValues} />
)
}
}
const Confirm = ({ children, visible, onAccept, onDecline, onChangeValues }) => {
return(
<TestConfirm onChangeValues={onChangeValues} />
)
}
class TestConfirm extends Component {
render() {
return(
<Screen>
<DropDownMenu
onOptionSelected={(zone) => {
// run passed prop with the value
this.props.onChangeValues({type: 'zone', value: zone});
this.setState({ selectedZone: zone, selectedCity: zone.children[0] });
}}
/>
<DropDownMenu
onOptionSelected={(city) => {
// run passed prop with the value
this.props.onChangeValues({type: 'city', value: city});
this.setState({ selectedCity: city })
}}
/>
</Screen>
)
}
}
how to navigate from LoginForm.js to product.js ?
route.js
import React from 'react';
import { StyleSheet,View,Text } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Home from './pages/home';
import Products from './pages/product';
// import Products from './pages/components/LoginForm';
const navigation = StackNavigator({
Home : { screen: Home },
// Login : { screen: LoginForm },
Products : { screen: Products },
});
export default navigation;
home.js
import React from 'react';
import { StyleSheet, Text, View, Button, StatusBar, Image } from 'react-native';
import LoginForm from './components/LoginForm';
export default class Home extends React.Component {
static navigationOptions = {
header: null
};
render() {
return (
<View style = { styles.container }>
<StatusBar
backgroundColor="#007ac1" barStyle="light-content"/>
<View style= { styles.logoContainer }>
<Image style = {styles.logo} source={require('../images/logo.png')} />
</View>
<View style= { styles.formContainer }>
<LoginForm />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#03a9f4'
},
logoContainer: {
flexGrow: 1, justifyContent:'center', alignItems:'center'
},
logo: {
width: 80, height: 80
},
formContainer: {
}
});
LoginForm.js
import React from 'react';
import { StyleSheet, Text, View ,TextInput, TouchableOpacity } from 'react-native';
export default class LoginForm extends React.Component {
constructor(props){
super(props)
this.state={
userName:'',
password:'',
type:'A'
}
}
userLogin = () =>{
const { userName } = this.state;
const { password } = this.state;
const { type } = this.state;
fetch('http://192.168.0.4:3000/notes',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body:JSON.stringify({
userName : userName,
password : password,
type : type
})
})
.then((response)=> response.json())
.then((responseJson) => {
if(responseJson.response.success == true) {
// alert(responseJson.response.result);
navigate('Products');
}else{
alert(responseJson.response.result);
}
})
.catch((error)=>{
console.error(error);
})
}
render() {
return (
<View style = {styles.container}>
<TextInput
underlineColorAndroid="transparent"
placeholder="Username or Email"
placeholderTextColor = "rgba(255,255,255,0.7)"
returnKeyType="next"
onSubmitEditing={() => this.passwordInput.focus()}
onChangeText = {userName => this.setState({userName})}
style={styles.input} />
<TextInput
placeholder="Password"
underlineColorAndroid="transparent"
secureTextEntry
returnKeyType="go"
placeholderTextColor = "rgba(255,255,255,0.7)"
ref = {(input) => this.passwordInput = input}
onChangeText = {password => this.setState({password})}
style={styles.input} />
<TouchableOpacity style={styles.buttonContainer} onPress={this.userLogin} >
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
container : {
padding:20
},
input: {
height:40, backgroundColor: 'rgba(255,255,255,0.2)', marginBottom:20,
color:'#FFF', paddingHorizontal:10, borderRadius:5
},
buttonContainer: {
backgroundColor: "#2980b9", paddingVertical:10, borderRadius:5
},
buttonText: {
textAlign :'center', color:'#FFFFFF', fontWeight:'700'
}
});
product.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default class Product extends React.Component {
static navigationOptions = {
// title: 'Home',
header: null
};
render() {
return (
<View style = { styles.container }>
<Text> Product Page open </Text>
<Button
title="Go to Home"
onPress={() => this.props.navigation.navigate('Home')}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Make LoginForm as part of navigator (it is currently commented). Then inside the userLogin function use this.props.navigation.navigate('Products') to navigate, take a look at the navigation doc
userLogin = () =>{
...
fetch('http://192.168.0.4:3000/notes',{
...
})
.then((response)=> response.json())
.then((responseJson) => {
if(responseJson.response.success == true) {
// alert(responseJson.response.result);
this.props.navigation.navigate('Products');
}else{
alert(responseJson.response.result);
}
})
.catch((error)=>{
console.error(error);
})
}
Hope this will help!