React Native Expo Infinite Loading State - javascript

This is probably a dumb question, but I've been following some react native / expo tutorials on how to make a login screen with Firebase. The tutorial I followed also made a loading screen (using a loading state) that will display while Firebase is connecting. Unfortunately, the loading state never ends for me, and I don't know how to fix it.
Here is my Navigator.js file:
import React, { useReducer } from "react";
import { View, ActivityIndicator } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from "#react-navigation/stack";
import { createDrawerNavigator } from "#react-navigation/drawer";
import { AuthContext } from '../contexts/UserContext';
import { firebase } from "../utils/FirebaseConfig";
import Login from "../screens/Login";
import Signup from "../screens/Signup";
import Home from "../screens/Home";
const Drawer = createDrawerNavigator();
const RootStack = createStackNavigator();
export default AppNavigation = (props) => {
const initialLoginState = {
isLoading: true,
user: null,
};
const loginReducer = (prevState, action) => {
switch (action.type) {
case 'LOGIN':
return {
...prevState,
user: action.user,
isLoading: false,
};
case 'LOGOUT':
return {
...prevState,
user: null,
isLoading: false,
};
case 'REGISTER':
return {
...prevState,
user: action.user,
isLoading: false,
};
}
};
const [loginState, dispatch] = useReducer(loginReducer, initialLoginState);
const authContext = React.useMemo(() => ({
signIn: async (email, password) => {
return firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(async (userCred) => {
dispatch({ type: 'LOGIN', user: userCred.user });
return true;
}).catch((error) => {
if (error.code === "auth/user-disabled") {
alert("User disabled!");
}
if (error.code === "auth/invalid-email") {
alert("That email address is invalid!");
}
if (error.code === "auth/user-not-found") {
alert("User not found, please sign up!");
}
if (error.code === "auth/wrong-password") {
alert("Wrong password!");
}
return false;
})
},
signOut: async () => {
return firebase.auth().signOut().then(async () => {
dispatch({ type: 'LOGOUT' });
});
},
signUp: (email, password) => {
return firebase.auth().createUserWithEmailAndPassword(email, password).then((userCred) => {
dispatch({ type: 'REGISTER', user: userCred.user });
}).catch((error) => {
if (error.code === "auth/email-already-in-use") {
alert("That email address is already in use!");
}
if (error.code === "auth/invalid-email") {
alert("That email address is invalid!");
}
if (error.code === "auth/operation-not-allowed") {
alert("Operation is not allowed!");
}
if (error.code === "auth/weak-password") {
alert("The password is too weak!");
}
return false;
})
}
}), []);
if (loginState.isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" color="grey" />
</View>
);
}
return (
<AuthContext.Provider value={authContext}>
<NavigationContainer>
{loginState.user !== null ? (
<Drawer.Navigator >
<Drawer.Screen name="Home" user={loginState.user} component={Home} />
</Drawer.Navigator>
) :
(
<RootStack.Navigator headerMode='none'>
<RootStack.Screen name="Login" component={Login} />
<RootStack.Screen name="Signup" component={Signup} />
</RootStack.Navigator>
)
}
</NavigationContainer>
</AuthContext.Provider>
)
}
Here is my Home.js File:
import React from 'react';
import { useContext } from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import { AuthContext } from "../contexts/UserContext";
function Home(props) {
const { signOut } = useContext(AuthContext);
return (
<View style={{ flex: 1 }}>
<Text>Welcome</Text>
<Text>Email: {props.user?.email}</Text>
<Text>uid: {props.user?.uid}</Text>
<Text>displayName: {props.user?.displayName}</Text>
<Text>photo: {props.user?.photoURL}</Text>
<TouchableOpacity onPress={() => signOut()} style={{ flexDirection: "row", alignItems: "center", justifyContent: "center", width: "100%" }} >
<Text style={{ fontWeight: "bold", fontSize: 18 }}>Logout</Text>
</TouchableOpacity>
</View>
);
}
export default Home;
Here is the Login.js file:
import React, { useContext, useState } from 'react';
import { KeyboardAvoidingView, View, Text, TextInput } from 'react-native';
import { AuthContext } from "../contexts/UserContext";
function Login(props) {
const [data, setData] = useState({
email: "",
password: ""
})
const { signIn } = useContext(AuthContext);
const emailInputChange = (val) => {
setData({
...data,
email: val
})
}
const passwordChange = (val) => {
setData({
...data,
password: val
});
}
const LoginHandle = () => {
signIn(data.email, data.password)
}
return (
<KeyboardAvoidingView>
<View style={{ flex: 1 }}>
<Text>Email: </Text>
<View >
<TextInput
placeholder="Email"
autoCapitalize="none"
onChangeText={(val) => emailInputChange(val)}
/>
</View>
<Text>Password: </Text>
<View>
<TextInput
placeholder="Password"
autoCapitalize="none"
secureTextEntry={true}
onChangeText={(val) => passwordChange(val)}
/>
</View>
<TouchableOpacity onPress={() => LoginHandle()} style={{ width: "100%", height: 50, justifyContent: "center", alignItems: "center", borderRadius: 10 }}>
<Text style={{ color: "#FFF", fontSize: 18, fontWeight: "bold" }}>Login</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}
export default Login;
And finally, the Signup.js file:
import React, { useContext, useState } from 'react';
import { KeyboardAvoidingView, View, Text, TextInput } from 'react-native';
import { AuthContext } from "../contexts/UserContext";
function Signup(props) {
const [data, setData] = useState({
email: "",
password: ""
})
const { signUp } = useContext(AuthContext);
const emailInputChange = (val) => {
setData({
...data,
email: val
})
}
const passwordChange = (val) => {
setData({
...data,
password: val
});
}
const SignupHandle = () => {
signUp(data.email, data.password)
}
return (
<KeyboardAvoidingView>
<View style={{ flex: 1 }}>
<Text>Email: </Text>
<View >
<TextInput
placeholder="Email"
autoCapitalize="none"
onChangeText={(val) => emailInputChange(val)}
/>
</View>
<Text>Password: </Text>
<View>
<TextInput
placeholder="Password"
autoCapitalize="none"
secureTextEntry={true}
onChangeText={(val) => passwordChange(val)}
/>
</View>
<TouchableOpacity onPress={() => SignupHandle()} style={{ width: "100%", height: 50, justifyContent: "center", alignItems: "center", borderRadius: 10 }}>
<Text style={{ color: "#FFF", fontSize: 18, fontWeight: "bold" }}>Signup</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}
export default Signup;

Related

Firebase error when calling a displayName

I am having issues when a user signs up using firebase auth, I am unable to capture the username so that it can be used in other parts of the app.
The error that i see in the console is:
"Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field displayName in document"...)
Would really appreciate if someone can point me to where the mistake is. Here are my files:
AuthProvider.js
import React, { createContext, useState } from "react";
import { auth, db } from "../firebase";
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider
value={{
user,
setUser,
login: async (email, password) => {
try {
await auth.signInWithEmailAndPassword(email, password);
} catch (e) {
console.log(e);
}
},
register: async (email, password, display_name) => {
try {
await auth
.createUserWithEmailAndPassword(email, password)
.then(async (res) => {
const userInfo = {
displayName: display_name,
};
await db
.collection("users")
.doc(res.user.uid)
.set(userInfo)
.then(() => {
console.log("user added")
console.log(res);
});
});
} catch (e) {
console.log(e);
}
},
logout: async () => {
try {
await auth.signOut();
} catch (e) {
console.log(e);
}
},
}}
>
{children}
</AuthContext.Provider>
);
};
SignUpScreen.js
import React, { useContext, useState } from "react";
import {
View,
Text,
TouchableOpacity,
Image,
Platform,
StyleSheet,
ScrollView,
Alert,
} from "react-native";
import FormInput from "../components/FormInput";
import FormButton from "../components/FormButton";
import SocialButton from "../components/SocialButton";
import { AuthContext } from "../navigation/AuthProvider";
const SignupScreen = ({ navigation }) => {
const [display_name, setDisplay_Name] = useState();
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [confirmPassword, setConfirmPassword] = useState();
const { register } = useContext(AuthContext);
const registerCheck = () => {
if (
display_name != "" &&
email != "" &&
password != "" &&
confirmPassword != ""
) {
if (password == confirmPassword) {
register(email, password);
} else {
Alert.alert("Oops! Passwords did not match");
}
} else {
Alert.alert("Oops! Some information is missing");
}
console.log(display_name, email, password, confirmPassword);
};
return (
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.text}>Create an Account</Text>
<FormInput
labelValue={display_name}
onChangeText={(userDisplay_Name) => setDisplay_Name(userDisplay_Name)}
placeholderText="Name"
iconType="user"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
<FormInput
labelValue={email}
onChangeText={(userEmail) => setEmail(userEmail)}
placeholderText="Email"
iconType="user"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
<FormInput
labelValue={password}
onChangeText={(userPassword) => setPassword(userPassword)}
placeholderText="Password"
iconType="lock"
secureTextEntry={true}
/>
<FormInput
labelValue={confirmPassword}
onChangeText={(userConfirmPassword) =>
setConfirmPassword(userConfirmPassword)
}
placeholderText="Confirm Password"
iconType="lock"
secureTextEntry={true}
/>
<FormButton
buttonTitle="Sign Up"
onPress={() => registerCheck(email, password)}
/>
<View style={styles.textPrivate}>
<Text style={styles.color_textPrivate}>
By registering, you confirm that you accept our{" "}
</Text>
<TouchableOpacity onPress={() => alert("Terms Clicked!")}>
<Text style={[styles.color_textPrivate, { color: "#e88832" }]}>
Terms of service
</Text>
</TouchableOpacity>
<Text style={styles.color_textPrivate}> and </Text>
<Text style={[styles.color_textPrivate, { color: "#e88832" }]}>
Privacy Policy
</Text>
</View>
<SocialButton
buttonTitle="Sign Up with Facebook"
btnType="facebook"
color="#4867aa"
backgroundColor="#e6eaf4"
onPress={() => {}}
/>
<SocialButton
buttonTitle="Sign Up with Google"
btnType="google"
color="#de4d41"
backgroundColor="#f5e7ea"
onPress={() => {}}
/>
<TouchableOpacity
style={styles.navButton}
onPress={() => navigation.navigate("Login")}
>
<Text style={styles.navButtonText}>Have an account? Sign In</Text>
</TouchableOpacity>
</ScrollView>
);
};
export default SignupScreen;
const styles = StyleSheet.create({
container: {
backgroundColor: "#f9fafd",
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
},
text: {
fontFamily: "Helvetica",
fontSize: 28,
marginBottom: 10,
color: "#051d5f",
},
navButton: {
marginTop: 15,
},
navButtonText: {
fontSize: 18,
fontWeight: "500",
color: "#2e64e5",
fontFamily: "Helvetica",
},
textPrivate: {
flexDirection: "row",
flexWrap: "wrap",
marginVertical: 35,
justifyContent: "center",
},
color_textPrivate: {
fontSize: 13,
fontWeight: "400",
fontFamily: "Helvetica",
color: "grey",
},
});

TypeError: undefined is not an object (evaluating 'navigation.replace')

MY login page
import React, { useState } from 'react'
import { TouchableOpacity, StyleSheet, View, ImageBackground } from 'react-native'
import { Text } from 'react-native-paper'
import Logo from '../Component/Logo'
import Header from '../Component/Header'
import Button from '../Component/Button'
import TextInput from '../Component/Inputtext'
import BackButton from '../Component/Backbutton'
import { theme } from '../core/theme'
import { emailValidator } from '../Component/emailval'
import { passwordValidator } from '../Component/Passwordval'
export default function LoginScreen({ navigation }) {
const [email, setEmail] = useState({ value: '', error: '' })
const [password, setPassword] = useState({ value: '', error: '' })
const onLoginPressed = () => {
const emailError = emailValidator(email.value)
const passwordError = passwordValidator(password.value)
if (emailError || passwordError) {
setEmail({ ...email, error: emailError })
setPassword({ ...password, error: passwordError })
return
}
navigation.reset({
index: 0,
routes: [{ name: 'Dashboard' }],
})
}
return (
<ImageBackground style={styles.image} source={require('../imgs/back.png') }>
<View>
<BackButton />
<Logo />
<Header style={styles.header}>Welcome back.</Header>
<TextInput
label="Email"
returnKeyType="next"
value={email.value}
onChangeText={(text) => setEmail({ value: text, error: '' })}
error={!!email.error}
errorText={email.error}
autoCapitalize="none"
autoCompleteType="email"
textContentType="emailAddress"
keyboardType="email-address"
style={styles.textmail}
/>
<TextInput
label="Password"
returnKeyType="done"
value={password.value}
onChangeText={(text) => setPassword({ value: text, error: '' })}
error={!!password.error}
errorText={password.error}
secureTextEntry
style={styles.textmail}
/>
<View style={styles.forgotPassword}>
<TouchableOpacity
onPress={() => navigation.navigate('ResetPasswordScreen')}
>
<Text style={styles.forgot}>Forgot your password?</Text>
</TouchableOpacity>
</View>
<Button mode="contained" onPress={onLoginPressed} style={styles.login}>
Login
</Button>
<View style={styles.row}>
<Text>Don’t have an account? </Text>
<TouchableOpacity onPress={() => navigation.replace('login')}>
<Text style={styles.link}>Sign up</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
)
}
const styles = StyleSheet.create({
forgotPassword: {
width: '100%',
alignItems: 'flex-end',
marginBottom: 24,
},
row: {
flexDirection: 'row',
marginTop: 4,
},
forgot: {
fontSize: 13,
color: '#414757',
},
link: {
fontWeight: 'bold',
color: '#560CCE',
},
header: {
fontSize: 21,
color: '#560CCE',
fontWeight: 'bold',
paddingVertical: 12,
},
image: {
width:'100%',
height: '100%',
},
textmail:{
backgroundColor:"#ffffff",
width:"90%",
alignSelf:'center',
borderRadius:40,
},
login:{
width:"70%"
}
})
App js::
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import OnboardingScreen from './Component/Onboardingscreen';
import LoginScreen from './Component/Loginscreen';
import Forgotpass from './Component/Forgotpassword';
import RegisterScreen from './Component/SignupScreen';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useEffect } from 'react';
const AppStack = createStackNavigator();
const App =() => {
const [isFirstLaunch, setIsFirstLaunch,] = React.useState(null);
useEffect(() => {
AsyncStorage.getItem('alreadyLaunched').then(value => {
if(value == null) {
AsyncStorage.setItem('alreadyLaunched','true');
setIsFirstLaunch(true);
} else {
setIsFirstLaunch(false);
}
});
}, []);
if (isFirstLaunch == null) {
return null;
} else if ( isFirstLaunch == true ){
return (
<NavigationContainer>
<AppStack.Navigator
headerMode='none'
>
<AppStack.Screen name="OnboardingScreen" component={OnboardingScreen}/>
<AppStack.Screen name='login' component={LoginScreen} />
<AppStack.Screen name="RegisterScreen" component={RegisterScreen} />
<AppStack.Screen name="ResetPasswordScreen" component={Forgotpass} />
</AppStack.Navigator>
</NavigationContainer>
);
} else {
return <LoginScreen />;
}
}
export default App;
Error occur while i pressing "forgot password" and "signup" ,
all dependency is addad ,
it shows onpress error and i added error screenshot also there are following below,
ERROR TypeError: undefined is not an object (evaluating 'navigation.replace')
ERROR TypeError: undefined is not an object (evaluating 'navigation.replace')
Try using the useNavigation() hook:
import { useNavigation } from '#react-navigation/native';
export default function LoginScreen() {
const navigation = useNavigation();
return (
...
<TouchableOpacity onPress={() => navigation.replace('login')}>
<Text style={styles.link}>Sign up</Text>
</TouchableOpacity>
...
);
}
Single data in a array is deleted in api data so it's show
null is a not an object
Solution:give the absent value = null;

Message not showing up in my react native chat bot

I'm making a chat bot app in react native and I am facing some difficulty in showing the messages that are saved in my firebase. The message box shows up empty. Moreover, three messages show up whereas there is only one message in my firebase. I am using React-Redux for state management and react-native-router-flux for navigation
Here is the code of my Login.js:
import React, {Component} from 'react'
import {View, Text, TouchableOpacity, StatusBar, ImageBackground} from 'react-native'
import {connect} from 'react-redux'
import {login, loginUser} from '../actions'
import {Input, Card, Button, Spinner} from './common'
class Login extends Component {
loginUser() {
const {email, password} = this.props
this.props.loginUser({email, password})
}
renderButton() {
if(this.props.loading) {
return <Spinner size='large' />
}
return (
<Button style={{backgroundColor: '#2D99FC', color: 'white'}}
text='Sign in'
onPress={this.loginUser.bind(this)}
/>
)
}
render() {
return(
<ImageBackground
style={{width: '100%', height: '100%'}}
source={require('../assets/images/bg.jpg')}
>
<StatusBar hidden />
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text style={{fontSize: 25, fontWeight: 'bold', margin: 10}}>Login</Text>
<Text style={{color: 'grey', margin: 10}}>Stay Connected</Text>
<Card>
<Input
placeholder='name#example.com'
iconName='user'
value={this.props.email}
onChangeText={value => this.props.login({prop: 'email', value})}
/>
<Input
placeholder="******"
iconName='lock'
secureTextEntry
value={this.props.password}
onChangeText={value => this.props.login({prop: 'password', value})}
/>
<Text style={{fontSize: 20, color: 'red'}}>
{this.props.error}
</Text>
{this.renderButton()}
<TouchableOpacity>
<Text style={{color:'#2D99FC', fontWeight: 'bold', margin: 10, marginBottom: 30}}>Forgot Password?</Text>
</TouchableOpacity>
<View style={{flexDirection: 'row', margin: 10}}>
<Text>Don't have an account? </Text>
<TouchableOpacity>
<Text style={{color:'#2D99FC', fontWeight: 'bold'}}>Sign Up</Text>
</TouchableOpacity>
</View>
</Card>
</View>
</ImageBackground>
);
}
}
const mapStateToProps = state => {
const {email, password, loading, error} = state.auth
return {email, password, loading, error}
}
export default connect(mapStateToProps, {login, loginUser})(Login)
Here is my code of AuthAction.js:
import {AsyncStorage} from 'react-native'
import firebase from 'firebase'
import {Actions} from 'react-native-router-flux'
import User from '../User'
import {REGISTER, SIGN_UP_USER, SIGN_UP_USER_SUCCESS, SIGN_UP_USER_FAIL, LOGIN, LOGIN_USER, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL, UPDATE_USERS} from './types'
export const register = ({prop, value}) => {
return {
type: REGISTER,
payload: {prop, value}
}
}
export const createUser = ({email, password, conPass, name}) => {
return(dispatch) => {
dispatch({type: SIGN_UP_USER})
if(password !== conPass) {
signupUserFail(dispatch, 'Passwords do not match')
}
else {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => {
signupUserSuccess(dispatch, user)
addData(name, email)
})
.catch(() => signupUserFail(dispatch, 'Authentication Failed'))
}
}
}
const addData = async (name, email) => {
await AsyncStorage.setItem('userName', name)
await AsyncStorage.setItem('userEmail', email)
User.name = name
User.email = email
firebase.database().ref('users/' + User.name).set({name, email})
}
const signupUserSuccess = (dispatch, user) => {
dispatch({
type: SIGN_UP_USER_SUCCESS,
payload: user
})
}
const signupUserFail = (dispatch, error) => {
dispatch({
type: SIGN_UP_USER_FAIL,
payload: error
})
}
export const login = ({prop, value}) => {
return {
type: LOGIN,
payload: {prop, value}
}
}
export const loginUser = ({email, password}) => {
return(dispatch) => {
dispatch({type: LOGIN_USER})
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(() => loginUserFail(dispatch, 'Authentication Failed'))
}
}
const loginUserSuccess = (dispatch, user) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user
})
firebase.database().ref('users')
.on('child_added', (val) => {
let person = val.val()
person.name = val.key
dispatch({type: UPDATE_USERS, payload: person})
})
Actions.chat()
}
const loginUserFail = (dispatch, error) => {
dispatch({
type: LOGIN_USER_FAIL,
payload: error
})
}
Here is my code to AuthReducer.js:
import {REGISTER, SIGN_UP_USER, SIGN_UP_USER_SUCCESS, SIGN_UP_USER_FAIL, LOGIN, LOGIN_USER, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL, UPDATE_USERS} from '../actions/types'
import User from '../User'
const INITIAL_STATE = {email: '', password: '', conPass: '', loading: false, error: '', user: null, name: '', user: []}
export default (state = INITIAL_STATE, action) => {
console.log(action)
switch(action.type) {
//Registration
case REGISTER:
return {...state, [action.payload.prop]: action.payload.value}
case SIGN_UP_USER:
return {...state, loading: true, error: ''}
case SIGN_UP_USER_SUCCESS:
return {...state, ...INITIAL_STATE, user: action.payload}
case SIGN_UP_USER_FAIL:
return {...state, error: action.payload, password: '', conPass: '', loading: false}
//Login
case LOGIN:
return {...state, [action.payload.prop]: action.payload.value}
case LOGIN_USER:
return {...state, loading: true, error: ''}
case LOGIN_USER_SUCCESS:
return {...state, ...INITIAL_STATE, user: action.payload}
case LOGIN_USER_FAIL:
return {...state, error: action.payload, password: '', loading: false}
case UPDATE_USERS:
User.name = action.payload.name
User.email = action.payload.email
//default
default:
return state
}
}
Here is my code to Chat.js:
import React, {Component} from 'react'
import {View, SafeAreaView, Text, TextInput, TouchableOpacity, StatusBar, Dimensions, FlatList} from 'react-native'
import {connect} from 'react-redux'
import {messageChanged, sendMessage, messagesListFetch} from '../actions'
import { Header } from './common';
import User from '../User';
class Chat extends Component {
onMessageChange(text) {
this.props.messageChanged(text)
}
sendMessage() {
const {message} = this.props
this.props.sendMessage(message)
}
componentDidMount() {
this.props.messagesListFetch()
}
render() {
return(
<View>
<View>
<StatusBar hidden />
<Header text='Chat with Me' />
</View>
<SafeAreaView>
<FlatList
scrollEnabled
style={{padding: 10, height: Dimensions.get('window').height * 0.8}}
data={this.props.messageList}
renderItem={(item) => {
return(
<View style={{
flexDirection: 'row',
width: '60%',
alignSelf: item[0] === User.name ? 'flex-end' : 'flex-start',
backgroundColor: item[0] === User.name ? '#00897B' : '#7CB342',
borderRadius: 5,
marginBottom: 10
}}>
<Text style={{color: '#FFF', padding: 7, fontSize: 16}}>{item[1]}</Text>
<Text style={{color: '#EEE', padding: 3, fontSize: 12}}>{item[2]}</Text>
</View>
)
}}
keyExtractor={(item, index) => item[0]}
/>
<View style={{flexDirection: 'row', alignItems: 'center', marginHorizontal: 5}}>
<TextInput
style={styles.input}
placeholder='Type a message...'
value={this.props.message}
onChangeText={this.onMessageChange.bind(this)}
/>
<TouchableOpacity onPress={this.sendMessage.bind(this)} style={{paddingBottom: 10, marginLeft: 5}}>
<Text>Send</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</View>
);
}
}
const styles = {
input: {
padding: 10,
borderWidth: 1,
borderColor: '#CCC',
width: '80%',
marginBottom: 10,
borderRadius: 5,
},
}
const mapStateToProps = state => {
let messages = state.chat.messageList
let messageList = []
Object.keys(messages).map((key, index) => {
messageList.push(messages[key])
})
let message = state.chat.message
return {message, messageList}
}
export default connect(mapStateToProps, {messageChanged, sendMessage, messagesListFetch})(Chat)
Here is my code to ChatActions.js:
import firebase from 'firebase'
import {MESSAGE_CHANGED, MESSAGE_SENT, GET_MESSAGE_LIST} from './types'
import User from '../User'
export const messageChanged = (text) => {
return {
type: MESSAGE_CHANGED,
payload: text
}
}
export const sendMessage = (textMessage) => {
return(dispatch) => {
if(textMessage.length > 0) {
console.log(User.name)
let msgId = firebase.database().ref('messages').child(User.name).child('Bot').push().key
let updates = {}
let message = {
message: textMessage,
time: firebase.database.ServerValue.TIMESTAMP,
from: User.name
}
updates['messages/' + User.name + '/' + 'Bot' + '/' + msgId] = message
updates['messages/' + 'Bot' + '/' + User.name + '/' + msgId] = message
firebase.database().ref().update(updates)
dispatch({type: MESSAGE_SENT})
}
}
}
export const messagesListFetch = () => {
return(dispatch) => {
setTimeout(() => {
firebase.database().ref('messages').child(User.name).child('Bot')
.on('child_added', (value) => {
dispatch({type: GET_MESSAGE_LIST, payload: value.val()})
// console.log(value.val())
})
}, 1000)
}
}
Here is my code to ChatReducer.js:
import {MESSAGE_CHANGED, MESSAGE_SENT, GET_MESSAGE_LIST} from '../actions/types'
const INITIAl_STATE = {message: '', messageList: []}
export default (state = INITIAl_STATE, action) => {
switch(action.type) {
case MESSAGE_CHANGED:
return {...state, message: action.payload}
case MESSAGE_SENT:
return {...state, message: ''}
case GET_MESSAGE_LIST:
return {...state, messageList: action.payload}
default:
return state
}
}
Here is my User.js:
User = {
name: '',
email: ''
}
export default User
I want the message to show, and to show only once, not thrice. How can I do that? Can anyone help me here?

React Native Redux causing whole page to render upon calling function

I have an issue with React Native Redux where I am calling a Redux action from the onChangeText function from inside a TextField. Normally, an update like this would only cause the TextField itself to update, however the whole page is being re-rendered upon each call of the function.
Here is the code for the TextField. The method in question is this.props.updateURL(value)
<TextField label='Server'
value={this.props.profile.url}
labelFontSize={textFont(16)}
tintColor='#B3B2B6'
autoCapitalize="none"
autoCorrect={false}
returnKeyType={'next'}
blurOnSubmit={false}
autoFocus={!this.props.profile.edited}
style={styles.inputStyle}
selectionColor={CUSRSOR_COLOR}
editable={!this.props.profile.edited}
onChangeText={async value => {
this.props.updateURL(value)
}}
renderAccessory={()=>{
return(<TouchableOpacity onPress={this.handleScanPress} >
<Image source={ImgScan} style={{height: 25, width: 25, overflow:'visible', marginBottom:20, marginRight: 10}}/>
</TouchableOpacity>);
}}
>
</TextField>
This is for the Redux methods mapStateToProps and mapDispatchToProps:
const mapStateToProps = (state) => {
return {
profile : state.profileReducer,
deviceUid: state.GlobalReducer.deviceUid,
locationsList: state.LogsReducer.locationList,
errorList: state.ErrorsReducer.failedList,
watermarkText: state.GlobalReducer.watermarkText,
alertPresent: state.LogsReducer.alertPresent
}
};
const mapDispatchToProps = (dispatch) => {
return {
updateURL : (url) => dispatch(updateURL(url)),
updateUserName : (userName) => dispatch(updateUserName(userName)),
updatePassword : (password) => dispatch(updatePassword(password)),
updateDeviceName : (deviceName) => dispatch(updateDeviceName(deviceName)),
allFieldsEntered : (url,userName,password) => dispatch(allFieldsEntered(url,userName,password)),
loginDevice: (url,userName,password,deviceName,deviceId,navigation,existingUser) => dispatch(callLoginApi(url,userName,password,deviceName,deviceId,navigation,existingUser)),
updateFailureMessage: (message) => dispatch(updateFailureMessage(message)),
showLoader: () => dispatch(showLoader()),
hideLoader: () => dispatch(hideLoader()),
updateRegistrationSuccess: (value) => dispatch(updateRegistrationSuccess(value)),
checkForInternet: () => dispatch(checkConnectivity()),
getProfileDetails: async(isToken) => await dispatch(fetchProfileDetails(isToken)),
updateLocationSwitch: (value) => dispatch(updateLocationStatus(value)),
updateIsEdit: (value) => dispatch(updateIsEdit(value)),
storeRegistrationFlagInAsync: () => dispatch(storeRegistrationFlagInAsync()),
isDeviceConnected: (value) => dispatch(isDeviceConnected(value)),
requestLocationPermissions: () => dispatch(requestLocationPermissions()),
passwordChanged: (value) => dispatch(updateIsPasswordChanged(value)),
isEditPage: (value) => dispatch(isEditPage(value)),
getDeviceName: () => dispatch(getDeviceName()),
shouldEnableLocation: (value) => dispatch(shouldEnableLocation(value)),
fetchLocationList: () => dispatch(fetchLocations()),
syncRecords: (url,userName,password,locationList,deviceId,isFromError,shouldPresentErrorMsg) => dispatch(syncFailedRecords(url,userName,password,locationList,deviceId,isFromError,shouldPresentErrorMsg)),
fetchFailedRecords: (shouldShowLoader) => dispatch(fetchFailedRecords(shouldShowLoader)),
updateDeviceAction: (action,deviceId,url) => dispatch(performDeviceAction(action,deviceId,url)),
callLogoutApi: (userName,password) => dispatch(callLogoutApi(userName,password)),
syncDeviceActions: () => dispatch(syncDeviceActions()),
syncPendingUpdates: (url,userName,password,deviceId) => dispatch(syncPendingUpdates(url,userName,password,deviceId)),
fetchPendingLocationsList: () => dispatch(fetchPendingLocationsList()),
showPasswordChangeAlert: (alertFlag,navigation) => dispatch(handleUIForPasswordChange(alertFlag,navigation)),
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Profile);
Here are the reducers:
const initialState = {
url: '',
userName : '',
password : '',
deviceName : '',
resourceCode : '',
isDeviceConnected : false,
allFieldsFilled: false,
token: '',
gpsTrackingInterval : 5,
apiPostingInterval : 30,
failureMessage : '',
registered : false,
edited: false,
editPage: false,
isConnected: true,
shouldEnableLocation: false,
resourceDesc: '',
adminEmail: '',
companyName: ''
}
const profileReducer = (state=initialState,action) => {
switch (action.type) {
case actionTypes.UPDATE_URL :
return {
...state,
url: action.payload
}
...
}
This is the Redux action:
export const updateURL = (url) => {
return {
type: actionTypes.UPDATE_URL,
payload: url
};
};
Any help would be much appreciated.
import React, { Component } from 'react';
import {
StyleSheet, Text, View, TextInput, TouchableOpacity, Image,
KeyboardAvoidingView, ScrollView, SafeAreaView, Linking
} from 'react-native';
import { COLOR_BLACK, COLOR_GRAY_9, COLOR_TRANSPARENT, COLOR_GRAY_4 } from '../../../constants/colors';
import ImgProntoLogo from '../../../assets/images/pronto-logo.png';
import ImgPasswordVisibleIcon from '../../../assets/images/visibility.png';
import ImgUrl from '../../../assets/images/url.png';
import ImgBarcode from '../../../assets/images/scan-barcode.png';
import ImgUsernameIcon from '../../../assets/images/username.png';
import ImgPasswordIcon from '../../../assets/images/password.png';
import ImgPasswordHide from '../../../assets/images/password-hide.png';
import GlobalStyleSheet from '../../../constants/styles';
import {
PASSWORD, USERNAME, URL_CONNECT
} from '../../../constants/strings';
import { StackActions, NavigationActions } from 'react-navigation';
import Sync from '../../../utils/Syncing';
import { AsyncStorage } from 'react-native';
export default class Configuration extends Component {
constructor(props) {
super(props)
this.handleOpenURL = this.handleOpenURL.bind(this);
this.handleScanPress = this.handleScanPress.bind(this);
}
async componentWillMount() {
this.props.clearConfiguration();
this.props.checkConnectivity();
Linking.addEventListener('url', this.handleOpenURL);
Sync.removeDataFromUserTable();
Sync.removeDataFromCompanyTable();
}
componentDidMount() {
console.log("COMPONENT MOUNTING");
Linking.getInitialURL().then((url) => {
if (url) {
url = url.substring(18);
this.props.updateURL(url);
}
}).catch(err => console.error('An error occurred', err))
}
componentWillReceiveProps(props) {
console.log("WILL RECEIVE")
}
handleOpenURL = (event) => {
this.props.updateURL(event.url.substring(18))
}
copyRights() {
var currentYear = new Date().getFullYear().toString();
return '© '.concat(currentYear).concat(' Pronto Software Limited.All Rights Reserved.');
}
// Connect the device to the pronto connect
async connectDevice() {
this.props.showLoader();
this.props.resetConnectPasswordVisibility();
await this.props.connectDevice(this.props.configuration.url,
this.props.configuration.username, this.props.configuration.password);
let isDeviceConnected = await AsyncStorage.getItem("isConnected");
if (isDeviceConnected === "true") {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Register' })],
});
this.props.navigation.dispatch(resetAction);
}
this.props.hideLoader();
}
static navigationOptions = {
header: null
}
handleScanPress() {
const action = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Scanner' })],
});
this.props.navigation.push('Scanner');
}
render() {
return (
<SafeAreaView style={GlobalStyleSheet.container}>
<KeyboardAvoidingView style={GlobalStyleSheet.container} >
<View style={styles.headerLogoView}>
<Image source={ImgProntoLogo} style={styles.logo} />
</View>
<ScrollView keyboardShouldPersistTaps="handled" style={styles.scrollViewStyle}>
<View style={{ flex: 1, height: '100%' }}>
<View style={styles.viewContainer}>
<Text style={[GlobalStyleSheet.textHeading4, GlobalStyleSheet.marginTop10,
GlobalStyleSheet.marginBottom10]}>CONFIGURE DEVICE</Text>
<View style={[GlobalStyleSheet.textInputView, GlobalStyleSheet.marginBottom10]}>
<Image style={GlobalStyleSheet.iconInputBar} source={ImgUrl} />
<TextInput
underlineColorAndroid={COLOR_TRANSPARENT}
style={GlobalStyleSheet.textInput}
autoCapitalize='none'
placeholder={URL_CONNECT}
value={this.props.configuration.url}
onChangeText={(value) => { this.props.updateURL(value) }}
editable={!(this.props.configuration.isDeviceConnected)}
/>
<TouchableOpacity style={[GlobalStyleSheet.passwordTouchable]} onPress={this.handleScanPress}>
<Image style={[GlobalStyleSheet.passwordShowHideIcon]} source={ImgBarcode} />
</TouchableOpacity>
</View>
<View style={[GlobalStyleSheet.textInputView, GlobalStyleSheet.marginBottom10]}>
<Image style={GlobalStyleSheet.iconInputBar} source={ImgUsernameIcon} />
<View style={[GlobalStyleSheet.flexRow, { flex: 1 }]}>
<TextInput
placeholder={USERNAME}
underlineColorAndroid={COLOR_TRANSPARENT}
style={GlobalStyleSheet.textInput}
onChangeText={(value) => { this.props.updateUsername(value) }}
editable={!(this.props.configuration.isDeviceConnected)}
/>
</View>
</View>
<View style={[GlobalStyleSheet.textInputView, GlobalStyleSheet.marginBottom10]} >
<Image style={[GlobalStyleSheet.iconInputBar]} source={ImgPasswordIcon} />
<View style={[GlobalStyleSheet.flexRow, { flex: 1 }]}>
<TextInput
placeholder={PASSWORD}
underlineColorAndroid={COLOR_TRANSPARENT}
contextMenuHidden={true}
style={GlobalStyleSheet.textInput}
autoCapitalize='none'
onChangeText={(value) => { this.props.updatePassword(value) }}
editable={!(this.props.configuration.isDeviceConnected)}
secureTextEntry={!(this.props.configuration.passwordVisibility)} />
<TouchableOpacity style={[GlobalStyleSheet.passwordTouchable]}
onPress={() => {
if (!this.props.configuration.isDeviceConnected) {
this.props.togglePasswordVisibility(this.props.configuration.passwordVisibility)
}
}}>
{
this.props.configuration.passwordVisibility ?
(<Image style={[GlobalStyleSheet.passwordShowHideIcon]} source={ImgPasswordVisibleIcon} />) :
(<Image style={[GlobalStyleSheet.passwordShowHideIcon]} source={ImgPasswordHide} />)
}
</TouchableOpacity>
</View>
</View>
{
this.props.configuration.isDeviceConnected ?
(
<TouchableOpacity style={GlobalStyleSheet.touchableBarProcessed} disabled={true} >
<Text style={GlobalStyleSheet.textTouchableBarProcessed}>CONNECTED</Text>
</TouchableOpacity>
) :
(this.props.configuration.url != "" &&
this.props.configuration.username != "" && this.props.configuration.password != "" ?
(
<TouchableOpacity style={[GlobalStyleSheet.touchableBarEnabled]}
onPress={async () => { await this.connectDevice() }}>
<Text style={GlobalStyleSheet.textTouchableBarEnabled}>CONNECT</Text>
</TouchableOpacity>
) :
(
<TouchableOpacity style={[GlobalStyleSheet.touchableBarDisabled]} disabled={true}>
<Text style={[GlobalStyleSheet.textTouchableBarDisabled]}>CONNECT</Text>
</TouchableOpacity>
)
)
}
</View>
</View>
<View style={styles.copyRightsView}>
<Text style={GlobalStyleSheet.copyRightsText}>{this.copyRights()}</Text>
</View>
</ScrollView>
</KeyboardAvoidingView >
</SafeAreaView >
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
width: '100%',
backgroundColor: COLOR_GRAY_9,
},
headerLogoView: {
height: 50,
backgroundColor: COLOR_GRAY_9,
elevation: 5,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 2,
shadowOffset: { width: 2, height: 2, },
shadowColor: COLOR_BLACK,
shadowOpacity: 0.1,
},
logo: {
height: 40,
width: '80%',
resizeMode: 'contain',
},
viewContainer: {
marginLeft: 15,
marginRight: 15,
paddingBottom: 10
},
copyRightsView: {
alignItems: 'center',
minHeight: 40,
paddingBottom: 5,
},
scrollViewStyle: {
flex: 1,
height: '100%',
paddingTop: 10
},
});

Stack navigator giving me undefined error

I'm using https://facebook.github.io/react-native/docs/navigation.html by the way.
I'm trying to use the StackNavigator to go from Login.js to AboutDendro.js. What's wrong in my <Button/> component that's throwing that error in my iOS simulator?
Here's Login.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ScrollView, Text, TextInput, View, Button, StyleSheet } from 'react-native';
import { login } from '../redux/actions/auth';
import {AuthenticationDetails, CognitoUser, CognitoUserAttribute, CognitoUserPool} from '../lib/aws-cognito-identity';
import StackNavigator from 'react-navigation';
import AboutDendro from './AboutDendro';
const awsCognitoSettings = {
UserPoolId: 'something',
ClientId: 'something'
};
class Login extends Component {
constructor (props) {
super(props);
this.state = {
page: 'Login',
username: '',
password: ''
};
}
get alt () { return (this.state.page === 'Login') ? 'SignUp' : 'Login'; }
handleClick (e) {
e.preventDefault();
const userPool = new CognitoUserPool(awsCognitoSettings);
// Sign up
if (this.state.page === 'SignUp') {
const attributeList = [
new CognitoUserAttribute({ Name: 'email', Value: this.state.username })
];
userPool.signUp(
this.state.username,
this.state.password,
attributeList,
null,
(err, result) => {
if (err) {
alert(err);
this.setState({ username: '', password: '' });
return;
}
console.log(`result = ${JSON.stringify(result)}`);
this.props.onLogin(this.state.username, this.state.password);
}
);
} else {
const authDetails = new AuthenticationDetails({
Username: this.state.username,
Password: this.state.password
});
const cognitoUser = new CognitoUser({
Username: this.state.username,
Pool: userPool
});
cognitoUser.authenticateUser(authDetails, {
onSuccess: (result) => {
console.log(`access token = ${result.getAccessToken().getJwtToken()}`);
this.props.onLogin(this.state.username, this.state.password);
},
onFailure: (err) => {
alert(err);
this.setState({ username: '', password: '' });
return;
}
});
}
}
togglePage (e) {
this.setState({ page: this.alt });
e.preventDefault();
}
static navigationOptions = {
title: 'AboutDendro',
};
render() {
const { navigate } = this.props.navigation;
const App = StackNavigator({
Home: { screen: Login },
Profile: { screen: AboutDendro },
});
return (
<ScrollView style={{padding: 20}}>
<Button
title="Go to Jane's profile"
onPress={() =>
navigate('AboutDendro', { name: 'AboutDendro' })
}
/>
<Text style={{fontSize: 27}}>{this.state.page}</Text>
<TextInput
placeholder='Email Address'
autoCapitalize='none'
autoCorrect={false}
autoFocus={true}
keyboardType='email-address'
value={this.state.username}
onChangeText={(text) => this.setState({ username: text })} />
<TextInput
placeholder='Password'
autoCapitalize='none'
autoCorrect={false}
secureTextEntry={true}
value={this.state.password}
onChangeText={(text) => this.setState({ password: text })} />
<View style={{margin: 7}}/>
<Button onPress={(e) => this.handleClick(e)} title={this.state.page}/>
<View style={styles.firstView}>
<Text onPress={(e) => this.togglePage(e)} style={styles.buttons}>
{this.alt}
</Text>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
buttons: {
fontSize: 12,
color: 'blue',
flex: 1
},
firstView: {
margin: 7,
flexDirection: 'row',
justifyContent: 'center'
}
});
const mapStateToProps = (state, ownProps) => {
return {
isLoggedIn: state.auth.isLoggedIn
};
}
const mapDispatchToProps = (dispatch) => {
return {
onLogin: (username, password) => { dispatch(login(username, password)); }
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
It is because navigation is not in your props. It is a part of your App component you created. But you do nothing with this component.
You should have an App.js file, with your stackNavigator, set your Login component as your default component in your stackNavigator's parameters.
Take a look at this documentation
I try to refactor your code.
in component render maybe you can just write :
render() {
const { navigate } = this.props.navigation;
return (
<ScrollView style={{padding: 20}}>
<Button
title="Go to Jane's profile"
onPress={() =>
navigate('Profile', { name: 'AboutDendro' })
}
/>
<Text style={{fontSize: 27}}>{this.state.page}</Text>
<TextInput
placeholder='Email Address'
autoCapitalize='none'
autoCorrect={false}
autoFocus={true}
keyboardType='email-address'
value={this.state.username}
onChangeText={(text) => this.setState({ username: text })} />
<TextInput
placeholder='Password'
autoCapitalize='none'
autoCorrect={false}
secureTextEntry={true}
value={this.state.password}
onChangeText={(text) => this.setState({ password: text })} />
<View style={{margin: 7}}/>
<Button onPress={(e) => this.handleClick(e)} title={this.state.page}/>
<View style={styles.firstView}>
<Text onPress={(e) => this.togglePage(e)} style={styles.buttons}>
{this.alt}
</Text>
</View>
</ScrollView>
);
}
}
And you separate component StackNavigation below component render() like:
const App = StackNavigator({
Home: { screen: Login },
Profile: { screen: AboutDendro },
});
And then import component App in your index.ios.js like:
import './Login';
just that. Maybe my answer can help you.

Categories