I am trying to create a social media app with React Native / Expo and Firebase, and I have successfully been able to create accounts and login, but I am still trying to figure out how to get user data such as username when the user logs in. Basically, when I log in or create an account, I want the profile page to show the username and profile picture associated with the user that logged in, but I'm not sure how to do that. It probably has something to do with the AuthStateChanged() function or something like that, but I'm not sure.
Here is my App.js file:
import 'react-native-gesture-handler';
import React, { useState } from 'react';
import { LogBox, Text, View } from 'react-native';
import AppLoading from 'expo-app-loading';
import * as Font from 'expo-font';
import Feather from '#expo/vector-icons/Feather'
import { useFonts, Nunito_400Regular as NunitoRegular, Nunito_700Bold as NunitoBold } from '#expo-google-fonts/nunito';
import { NavigationContainer, DefaultTheme } from '#react-navigation/native';
import Navigator from './src/navigation/index';
import * as firebase from "firebase";
import "firebase/auth";
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "AIzaSyB1TxcRpLQq0Zqs0f0FvPitIto0tZo_0xM",
authDomain: "shutter-42e70.firebaseapp.com",
projectId: "shutter-42e70",
storageBucket: "shutter-42e70.appspot.com",
messagingSenderId: "149059508529",
appId: "1:149059508529:web:0dbc5bbbb75bf022ef7810"
};
if (firebase.apps.length === 0) {
firebase.initializeApp(firebaseConfig);
}
// The theme we'll be using for our navigator
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: '#FAFAFA'
},
};
// Loads the Feather icons (https://docs.expo.io/guides/icons/)
function cacheFonts(fonts) {
return fonts.map(font => Font.loadAsync(font));
}
export default function App() {
const [assetsReady, setAssetsReady] = useState(false);
async function _loadFonts() {
const iconFontAssets = cacheFonts([Feather.font])
await Promise.all([...iconFontAssets]);
}
// Loads the Nunito font (https://docs.expo.io/guides/using-custom-fonts/)
let [fontsLoaded] = useFonts({
NunitoRegular, NunitoBold
});
// If the fonts or assets are not loaded, we show a default App Loading screen.
// Otherwise, we return our Photo Sharing App!
if (!fontsLoaded || !assetsReady) {
return <AppLoading
startAsync={_loadFonts}
onFinish={() => setAssetsReady(true)}
onError={console.warn}
/>
}
return (
<NavigationContainer theme={MyTheme}>
<Navigator />
</NavigationContainer>
);
}
Here is my Login.js file:
import React from 'react';
import { StyleSheet, View, Text, Image, TextInput, TouchableOpacity } from 'react-native';
import theme from '../../assets/themes';
import { Formik } from 'formik';
import { Octicons, Fontisto } from '#expo/vector-icons';
import Separator from './Separator';
import KeyBoardAvoidingWrapper from './KeyboardAvoidingWrapper';
import firebase from 'firebase';
var errorMsg = '...'
const Login = ({navigation}) => {
return (
<KeyBoardAvoidingWrapper>
<View>
<View style = {styles.StyledContainer}>
<View style = {styles.InnerContainer}>
<Image style = {styles.PageLogo} resizeMode = "cover" source = {require('./../../assets/images/logo.png')} />
<Text style = {styles.PageTitle}>Shutter</Text>
<Text style = {styles.TagLine}>Social Media for Photographers</Text>
</View>
</View>
<Formik
initialValues = {{email: '', password: ''}}
onSubmit = {(values) => {
firebase.auth().signInWithEmailAndPassword(values.email, values.password)
.then((result) => {
navigation.navigate('Feed');
})
.catch((error) => {
alert(error)
})
}}
>
{({handleChange, handleBlur, handleSubmit, values}) => (
<View style = {styles.styledFormArea}>
<MyTextInput
label = " "
icon = "mail"
placeholder = "email#email.com"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('email')}
onBlur = {handleBlur('email')}
value = {values.email}
keyboardType = "email-address"
/>
<MyTextInput
label = " "
icon = "lock"
placeholder = "password"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('password')}
onBlur = {handleBlur('password')}
value = {values.password}
secureTextEntry = {true}
/>
<Text style = {styles.msgBox}>{errorMsg}</Text>
<TouchableOpacity onPress = {handleSubmit} style = {styles.loginButton}>
<Text style = {styles.loginButtonText}>Login</Text>
</TouchableOpacity>
<Separator />
<TouchableOpacity onPress = {handleSubmit} style = {styles.googleSigninButton}>
<Fontisto name = "google" color = {theme.colors.white} size = {25} ></Fontisto>
<Text style = {styles.googleSigninButtonText}>Sign in with Google</Text>
</TouchableOpacity>
<View style = {styles.signupLinkView}>
<Text style = {styles.signupText}>Don't have an account? </Text>
<TouchableOpacity style = {styles.signupLinkButton}>
<Text onPress = {() => navigation.navigate('Sign Up')} style = {styles.signupLinkText}>Sign up</Text>
</TouchableOpacity>
</View>
</View>
)}
</Formik>
</View>
</KeyBoardAvoidingWrapper>
);
};
const MyTextInput = ({label, icon, ...props}) => {
return (
<View>
<View style = {styles.leftIcon}>
<Octicons name = {icon} size = {30} color = {theme.colors.primary} />
</View>
<Text style = {styles.styledTextInput}>{label}</Text>
<TextInput style = {styles.textInput} {...props} />
</View>
)
}
const styles = StyleSheet.create({
StyledContainer: {
flex: 1,
padding: theme.spacing.m,
paddingTop: theme.spacing.l,
backgroundColor: theme.colors.white,
marginTop: 80,
},
InnerContainer: {
justifyContent: 'center',
alignItems: 'center',
},
PageLogo: {
width: 100,
height: 100,
},
PageTitle: {
...theme.textVariants.h1,
marginTop: theme.spacing.m,
},
TagLine: {
...theme.textVariants.body3,
},
styledFormArea: {
justifyContent: 'center',
marginHorizontal: theme.spacing.l,
borderRadius: theme.borderRadius.m,
marginTop: 40,
},
leftIcon: {
position: 'absolute',
zIndex: 1,
marginTop: 28,
marginLeft: 12,
},
styledTextInput: {
...theme.textVariants.body3,
},
textInput: {
backgroundColor: theme.colors.gray,
paddingVertical: 10,
paddingLeft: 50,
paddingRight: theme.spacing.l,
borderRadius: theme.borderRadius.m,
},
loginButton: {
backgroundColor: theme.colors.primary,
alignItems: 'center',
marginTop: 20,
paddingVertical: 8,
borderRadius: theme.borderRadius.m,
},
loginButtonText: {
...theme.textVariants.body2,
color: theme.colors.white,
},
msgBox: {
...theme.textVariants.body3,
alignSelf: 'center',
},
googleSigninButton: {
backgroundColor: theme.colors.primary,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginTop: 16,
paddingVertical: 8,
borderRadius: theme.borderRadius.m,
},
googleSigninButtonText: {
...theme.textVariants.body2,
color: theme.colors.white,
paddingLeft: 25,
},
signupLinkView: {
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
padding: theme.spacing.sm,
},
signupText: {
...theme.textVariants.body3,
},
signupLinkButton: {
},
signupLinkText: {
...theme.textVariants.body3,
opacity: 0.6,
},
})
export default Login;
Here is my Signup.js file:
import React from 'react';
import { StyleSheet, View, Text, Image, TextInput, TouchableOpacity } from 'react-native';
import theme from '../../assets/themes';
import { Formik } from 'formik';
import { Octicons } from '#expo/vector-icons';
import Separator from './Separator';
import KeyboardAvoidingWrapper from './KeyboardAvoidingWrapper';
import firebase from 'firebase';
var errorMsg = '...'
const SignUp = ({navigation}) => {
return (
<KeyboardAvoidingWrapper>
<View>
<View style = {styles.StyledContainer}>
<View style = {styles.InnerContainer}>
<Image style = {styles.PageLogo} resizeMode = "cover" source = {require('./../../assets/images/logo.png')} />
<Text style = {styles.PageTitle}>Shutter</Text>
<Text style = {styles.TagLine}>Social Media for Photographers</Text>
</View>
</View>
<Formik
initialValues = {{fullName: '', email: '', username: '', password: '', confirmPassword: ''}}
onSubmit = {(values) => {
firebase.auth().createUserWithEmailAndPassword(values.email, values.password)
.then((result) => {
firebase.firestore().collection("users")
.doc(firebase.auth().currentUser.uid)
.set({
fullName: values.fullName,
displayName: values.email,
username: values.username,
password: values.password,
})
if (values.password === values.confirmPassword)
navigation.navigate('Signup Options')
else
errorMsg = 'Passwords do not match'
})
.catch((error) => {
alert(error)
})
}}
>
{({handleChange, handleBlur, handleSubmit, values}) => (
<View style = {styles.styledFormArea}>
<MyTextInput
label = "Name"
icon = "person"
placeholder = "John Doe"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('fullName')}
onBlur = {handleBlur('fullName')}
value = {values.fullName}
/>
<MyTextInput
label = "Email"
icon = "mail"
placeholder = "email#email.com"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('email')}
onBlur = {handleBlur('email')}
value = {values.email}
keyboardType = "email-address"
/>
<MyTextInput
label = "Username"
icon = "person"
placeholder = "username"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('username')}
onBlur = {handleBlur('username')}
value = {values.username}
/>
<MyTextInput
label = "Password"
icon = "lock"
placeholder = "password"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('password')}
onBlur = {handleBlur('password')}
value = {values.password}
secureTextEntry = {true}
/>
<MyTextInput
label = "Confirm Password"
icon = "lock"
placeholder = "retype password"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('confirmPassword')}
onBlur = {handleBlur('confirmPassword')}
value = {values.confirmPassword}
secureTextEntry = {true}
/>
<Text style = {styles.msgBox}>{errorMsg}</Text>
<TouchableOpacity onPress = {handleSubmit} style = {styles.loginButton}>
<Text style = {styles.loginButtonText}>Sign Up</Text>
</TouchableOpacity>
<Separator />
<View style = {styles.signupLinkView}>
<Text style = {styles.signupText}>Already have an account? </Text>
<TouchableOpacity style = {styles.signupLinkButton}>
<Text onPress = {() => navigation.navigate('Login')} style = {styles.signupLinkText}>Login</Text>
</TouchableOpacity>
</View>
</View>
)}
</Formik>
</View>
</KeyboardAvoidingWrapper>
);
};
const onSignUp = ({values}) => {
console.log(values);
}
const MyTextInput = ({label, icon, ...props}) => {
return (
<View style = {styles.inputFieldView}>
<View style = {styles.leftIcon}>
<Octicons name = {icon} size = {30} color = {theme.colors.primary} />
</View>
<Text style = {styles.styledTextInput}>{label}</Text>
<TextInput style = {styles.textInput} {...props} />
</View>
)
}
const styles = StyleSheet.create({
StyledContainer: {
flex: 1,
padding: theme.spacing.m,
paddingTop: theme.spacing.l,
backgroundColor: theme.colors.white,
marginTop: 80,
},
InnerContainer: {
justifyContent: 'center',
alignItems: 'center',
},
PageLogo: {
width: 100,
height: 100,
},
PageTitle: {
...theme.textVariants.h1,
marginTop: theme.spacing.m,
},
TagLine: {
...theme.textVariants.body3,
},
inputFieldView: {
marginTop: 12,
},
styledFormArea: {
justifyContent: 'center',
marginHorizontal: theme.spacing.l,
borderRadius: theme.borderRadius.m,
marginTop: 40,
},
leftIcon: {
position: 'absolute',
zIndex: 1,
marginTop: 28,
marginLeft: 12,
},
styledTextInput: {
...theme.textVariants.body3,
},
textInput: {
backgroundColor: theme.colors.gray,
paddingVertical: 10,
paddingLeft: 50,
paddingRight: theme.spacing.l,
borderRadius: theme.borderRadius.m,
},
loginButton: {
backgroundColor: theme.colors.primary,
alignItems: 'center',
marginTop: 20,
paddingVertical: 8,
borderRadius: theme.borderRadius.m,
},
loginButtonText: {
...theme.textVariants.body2,
color: theme.colors.white,
},
msgBox: {
...theme.textVariants.body3,
alignSelf: 'center',
},
signupLinkView: {
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
padding: theme.spacing.sm,
},
signupText: {
...theme.textVariants.body3,
},
signupLinkButton: {
},
signupLinkText: {
...theme.textVariants.body3,
opacity: 0.6,
},
})
export default SignUp;
Sorry if my code isn't written very well and isn't very organized. I couldn't find very many good tutorials on firebase authentication so this is what I came up with after watching like 5 different firebase authentication tutorials lol. Any help would be greatly appreciated!
Also, here is the link to my github repo if you want to see my entire project file: github repo
You should use redux or React hooks to save user info into global state.
https://reactjs.org/docs/hooks-reference.html#usecontext
https://redux.js.org/introduction/getting-started
In the callback of signInWithEmailAndPassword() return user profile data
firebase.auth().signInWithEmailAndPassword(email, password)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
/* user:
- email
- uid
- displayName
- emailVerified
- phoneNumber
- photoURL
- metadata
...
*/
})
.catch((error) => {
// catch error
});
Then in your components/screens, you can call the state to show user's data.
Related
I am facing issues in implementing Webview navigation of website using back button as back button when pressed exits the app.
I implemented a button functionality that uses the browser functionality of going back to the previous page and next page. But, this was not an effective implementation.
Here's my webview code:
import React, { useEffect, useState, useRef } from "react";
import {
View,
Text,
StyleSheet,
SafeAreaView,
StatusBar,
Alert,
BackHandler,
} from "react-native";
import { State, TouchableOpacity } from "react-native-gesture-handler";
import * as firebase from "firebase";
import { loggingOut } from "../API/firebaseMethods";
import { WebView } from "react-native-webview";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import SignIn from "./SignIn";
import SignUp from "./SignUp";
import { useBackHandler } from "#react-native-community/hooks";
import NavigationView from "./NavigationView";
const Tab = createBottomTabNavigator();
const LENNY = "https://www.testbooking.lennyconsulting.com/";
const THEME_COLOR = "#000000";
export default function Dashboard({ navigation }) {
function backActionHandler() {
Alert.alert("", "Are Your Sure To Exit The App?", [
{
text: "No",
onPress: () => null,
style: "cancel",
},
{
text: "Yes",
onPress: () => BackHandler.exitApp(),
},
]);
return true;
}
useBackHandler(backActionHandler);
let currentUserUID = firebase.auth().currentUser.uid;
const [firstName, setFirstName] = useState("");
useEffect(() => {
async function getUserInfo() {
try {
let doc = await firebase
.firestore()
.collection("users")
.doc(currentUserUID)
.get();
if (!doc.exists) {
Alert.alert("No user data found!");
} else {
let dataObj = doc.data();
setFirstName(dataObj.firstName);
}
} catch (err) {
Alert.alert("There is an error.", err.message);
}
}
getUserInfo();
});
const handlePress = () => {
loggingOut();
navigation.replace("Home");
};
const AppStatusBar = ({ backgroundColor, ...props }) => {
return (
<View style={[styles.statusBar, backgroundColor]}>
<StatusBar backgroundColor={backgroundColor} {...props} />
</View>
);
};
const BAR_HEIGHT = StatusBar.currentHeight;
const styles = StyleSheet.create({
statusBar: {
height: BAR_HEIGHT,
},
});
const webViewRef = useRef();
const [canGoBack, setCanGoBack] = useState(false);
const [canGoForward, setCanGoForward] = useState(false);
const handleBackPress = () => {
webViewRef.current.goBack();
};
const handleForwardPress = () => {
webViewRef.current.goForward();
};
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={{ width: "100%", height: "100%" }}>
<WebView
ref={webViewRef}
source={{ uri: LENNY }}
onLoad={console.log("Loaded")}
onNavigationStateChange={(state) => {
const back = state.canGoBack;
const forward = state.canGoForward;
setCanGoBack(back);
setCanGoForward(forward);
}}
/>
<NavigationView
onBackPress={handleBackPress}
onForwardPress={handleForwardPress}
canGoBack={canGoBack}
canGoForward={canGoForward}
/>
<StatusBar style="auto" />
<View>
<Text style={styles.text}>Hi {firstName}</Text>
<TouchableOpacity style={styles.button} onPress={handlePress}>
<Text style={styles.buttonText}>Log Out</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
<SafeAreaView style={styles.topSafeArea} />
<SafeAreaView style={styles.bottomSafeArea}>
<AppStatusBar backgroundColor={THEME_COLOR} barStyle="light-content" />
</SafeAreaView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
topSafeArea: {
flex: 1,
backgroundColor: THEME_COLOR,
},
bottomSafeArea: {
flex: 1,
backgroundColor: THEME_COLOR,
},
button: {
width: 150,
padding: 5,
backgroundColor: "#ff9999",
borderWidth: 2,
borderColor: "white",
borderRadius: 15,
alignSelf: "center",
},
buttonText: {
fontSize: 20,
color: "white",
fontWeight: "bold",
textAlign: "center",
},
container: {
height: "100%",
width: "100%",
backgroundColor: "#3FC5AB",
alignItems: "center",
justifyContent: "center",
},
text: {
textAlign: "center",
fontSize: 20,
fontStyle: "italic",
marginTop: "2%",
marginBottom: "10%",
fontWeight: "bold",
color: "black",
},
titleText: {
textAlign: "center",
fontSize: 30,
fontWeight: "bold",
color: "#2E6194",
},
});
Please someone help me. I am new to React Native.
I have an array which displays a list of jobs with the radio button(each).If I click any radio button I want to get its value so far I'm getting an error input must be a function received undefined. how can I achieve something like this in react native?
Code
import React, {useState} from 'react';
import {View, Text, TextInput, Image,Button,Body,Pressable,ScrollView,Switch} from 'react-native';
export default function Home({ navigation}){
let roles = navigation.getParam('roles')
const [isEnabled, setIsEnabled] = useState(false);
const toggleSwitch = () => setIsEnabled(previousState => !previousState);
const handleClick = (data, e) => {
alert(e.target.value, data);
}
<View>
{
Object.keys(roles).map((key) => {
return (
<View>
<View style={styles.XYQHC}>
<Text>{roles[key]['name']}</Text>
<Switch
trackColor={{ false: "#767577", true: "#81b0ff" }}
thumbColor={isEnabled ? "#f5dd4b" : "#f4f3f4"}
ios_backgroundColor="#3e3e3e"
onValueChange={toggleSwitch}
value={isEnabled}
/>
<input type="radio" name="roles" value={roles[key]['name']} defaultChecked={roles[key]['id'] == 3 ? true : false } onClick={handleClick.bind(this, roles[key]['name'])}/>
</View>
</View>
)
})
}
</View>
};
I had to edit a little bit to make it work and to assume some input data but here is a working example of your code:
import React, { useState, useEffect } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
function RadioButton({ label, onPress, selected, style }) {
return (
<TouchableOpacity
style={[
{
flexDirection: 'row',
alignItems: 'center',
marginLeft: 12,
marginVertical: 20,
},
style,
]}
onPress={onPress}>
<View
style={{
height: 24,
width: 24,
borderRadius: 12,
borderWidth: 2,
borderColor: '#000',
alignItems: 'center',
justifyContent: 'center',
marginRight: 12,
}}>
{selected ? (
<View
style={{
height: 12,
width: 12,
borderRadius: 6,
backgroundColor: '#000',
}}
/>
) : null}
</View>
<Text>{label}</Text>
</TouchableOpacity>
);
}
export default function Home({ navigation }) {
// let status = navigation.getParam('status');
let status = 2;
// let roles = navigation.getParam('roles');
let roles = [
{
id: 1,
name: 'lawyer',
},
{
id: 2,
name: 'farmer',
},
{
id: 3,
name: 'architect',
},
];
const [isEnabled, setIsEnabled] = useState(false);
const [chosenRole, setChosenRole] = useState(false);
useEffect(() => {
roles.find((role) => {
if (role.id === status) {
setChosenRole(role);
return true;
}
return false;
});
}, []);
const handleClick = (data) => {
console.log(data);
setChosenRole(data);
};
return (
<View style={{ marginTop: 30 }}>
{roles.map((role) => {
return (
<View>
<RadioButton
label={role.name}
selected={role.name === chosenRole.name}
onPress={() => handleClick(role)}
/>
</View>
);
})}
</View>
);
}
Hi I'm getting the error undefined is not an object(evaluating 'navigation.navigate') after I'm submitting the form. I searched many google/stackoverflow answers but none of them helped me.
I'm not sure if this is cause by firebase or actual prop navigation. Any insights on this ???
Please see the code below:
// parent component
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import LoginForm from '../components/LoginForm';
const Login = () => {
return (
<View style={styles.mainWrapper}>
<Image style={styles.logo} title="Logo" source={require('../assets/box.png')}/>
<LoginForm/>
</View>
);
}
const styles = StyleSheet.create({
logo: {
width: 150,
height: 150,
marginTop: 55
},
mainWrapper: {
display: "flex",
alignItems: "center"
}
});
export default Login;
// login form component
import React, { useState } from 'react';
import { StyleSheet, Text, View, TextInput, TouchableOpacity, Alert} from 'react-native';
import firebase from 'firebase/app';
import 'firebase/auth';
import { firebaseConfig } from '../config';
if(!firebase.apps.length){
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
}
const auth = firebase.auth();
const LoginForm = ({navigation}) => {
const [email,setEmail] = useState('');
const [password, setPassword] = useState('');
const signIn = async() => {
try {
let response = await auth.signInWithEmailAndPassword(email,password);
if(response.user){
Alert.alert('logged in' + response.user.email);
navigation.navigate('Driver');
}
}catch(e){
Alert.alert(e.message);
}
};
return (
<View style={styles.formView}>
<TextInput
value={email}
placeholder="Email"
style={styles.input}
onChangeText={userEmail => setEmail(userEmail)}
autoCapitalize='none'
keyboardType='email-address'
autoCorrect={false}
/>
<TextInput
value={password}
placeholder="Password"
secureTextEntry={true}
style={styles.input}
onChangeText={userPassword => setPassword(userPassword)}
/>
<TouchableOpacity style={styles.submitBtn} title="Login" onPress={() => signIn()}>
<Text style={styles.appButtonText}>Login</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
formView: {
marginTop: 45,
display: "flex",
alignItems: "center",
},
input: {
marginTop: 20,
width: 300,
height: 40,
paddingHorizontal: 10,
borderRadius: 5,
backgroundColor: 'white',
},
submitBtn: {
backgroundColor: "#FFE17D",
color: "#E6646E",
fontWeight: "bold",
width: 150,
height: 40,
marginTop: 20,
borderColor: "#E6646E",
borderRadius: 5,
display: "flex",
justifyContent: "center",
borderWidth: 1,
},
appButtonText: {
fontSize: 18,
color: "#E6646E",
fontWeight: "bold",
alignSelf: "center",
textTransform: "uppercase"
}
});
Only the stack screens have access to the props navigation. You can try sending navigation to LoginForm but that works only if Login is a Stack Screen.
const Login = ({navigation}) => {
return (
<View style={styles.mainWrapper}>
<Image style={styles.logo} title="Logo" source={require('../assets/box.png')}/>
<LoginForm navigation={navigation}/>
</View>
);
}
Or you can have a look in the useNavigation hook
I know there have been similar questions, but I tried anyway and still can't find the solution.
I have a login screen, registration, chat and a test screen (where I use just to try to fix this error) I want to pass the name, email and avatar data that I get there from Login / Register, but it is returned to me that the object is undefined. I only corrected the error if I put the navigation as follows: Login or Register> Chat. However, I do not want to do so, I need to click on an image and direct to this chat. Apparently it's a common mistake, but I'm frustrated with trying to fix it (I'm new to React-Native)
Chat.js
import { GiftedChat } from "react-native-gifted-chat"; // 0.3.0
import firebaseSvc from "../FirebaseSvc";
type Props = {
name?: string,
email?: string,
avatar?: string
};
class Chat extends React.Component<Props> {
constructor(props) {
super(props);
}
static navigationOptions = ({ navigation }) => ({
title: (navigation.state.params || {}).name || "Chat!"
});
state = {
messages: []
};
get user() {
return {
name: this.props.navigation.state.params.name,
email: this.props.navigation.state.params.email,
avatar: this.props.navigation.state.params.avatar,
id: firebaseSvc.uid,
_id: firebaseSvc.uid // need for gifted-chat
};
}
render() {
return (
<GiftedChat
messages={this.state.messages}
onSend={firebaseSvc.send}
user={this.user}
/>
);
}
componentDidMount() {
firebaseSvc.refOn(message =>
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, message)
}))
);
}
componentWillUnmount() {
firebaseSvc.refOff();
}
}
export default Chat;
Login.js
import { Constants, ImagePicker, Permissions } from "expo";
import {
StyleSheet,
Text,
TextInput,
TouchableOpacity,
KeyboardAvoidingView,
View,
Button,
ImageEditor,
Image,
StatusBar,
LayoutAnimation
} from "react-native";
import firebaseSvc from "../FirebaseSvc";
import firebase from "firebase";
import { auth, initializeApp, storage } from "firebase";
import uuid from "uuid";
class Login extends React.Component {
state = {
name: "",
email: "",
password: "",
avatar: ""
};
// using Fire.js
onPressLogin = async () => {
console.log("pressing login... email:" + this.state.email);
const user = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
avatar: this.state.avatar
};
const response = firebaseSvc.login(
user,
this.loginSuccess,
this.loginFailed
);
};
loginSuccess = () => {
console.log("login successful, navigate to chat.");
this.props.navigation.navigate("TelaTeste", {
name: this.state.name,
email: this.state.email,
avatar: this.state.avatar
});
};
loginFailed = () => {
console.log("login failed ***");
alert("Login failure. Please tried again.");
};
onChangeTextEmail = email => this.setState({ email });
onChangeTextPassword = password => this.setState({ password });
render() {
LayoutAnimation.easeInEaseOut();
return (
<View style={styles.container}>
<KeyboardAvoidingView behavior="padding">
<Text style={styles.titulo}>{"CUDDLE"}</Text>
<View style={styles.errorMessage}>
{this.state.errorMessage && (
<Text style={styles.error}>{this.state.errorMessage}</Text>
)}
</View>
<View style={styles.form}>
<View>
<Text style={styles.inputTitle}>Email Address</Text>
<TextInput
style={styles.input}
autoCapitalize="none"
onChangeText={this.onChangeTextEmail}
value={this.state.email}
></TextInput>
</View>
<View style={{ marginTop: 32 }}>
<Text style={styles.inputTitle}>Password</Text>
<TextInput
style={styles.input}
secureTextEntry
autoCapitalize="none"
onChangeText={this.onChangeTextPassword}
value={this.state.password}
></TextInput>
</View>
</View>
<TouchableOpacity style={styles.button} onPress={this.onPressLogin}>
<Text style={{ color: "#FFF", fontWeight: "500" }}>Sign in</Text>
</TouchableOpacity>
<TouchableOpacity
style={{ alignSelf: "center", marginTop: 32 }}
onPress={() => this.props.navigation.navigate("Register")}
>
<Text style={{ color: "#414959", fontSize: 13 }}>
New to SocialApp?{" "}
<Text style={{ fontWeight: "500", color: "#5B2B80" }}>
Sign Up
</Text>
</Text>
</TouchableOpacity>
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
titulo: {
color: "#5B2B80",
fontSize: 30,
fontWeight: "bold",
textAlign: "center",
marginTop: 150
},
errorMessage: {
height: 72,
alignItems: "center",
justifyContent: "center",
marginHorizontal: 30
},
error: {
color: "#5B2B80",
fontSize: 13,
fontWeight: "600",
textAlign: "center"
},
form: {
marginBottom: 48,
marginHorizontal: 60
},
inputTitle: {
color: "#8A8F9E",
fontSize: 10,
textTransform: "uppercase"
},
input: {
borderBottomColor: "#8A8F9E",
borderBottomWidth: StyleSheet.hairlineWidth,
height: 40,
fontSize: 15,
color: "#161F3D"
},
button: {
marginHorizontal: 60,
backgroundColor: "#5B2B80",
borderRadius: 4,
height: 52,
alignItems: "center",
justifyContent: "center"
}
});
export default Login;
App.js
import Login from "./components/Login";
import CreateAccount from "./components/CreateAccount";
import Chat from "./components/Chat";
import TelaTeste from "./components/TelaTeste";
// Import React Navigation
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
const AppNavigator = createStackNavigator({
Login: { screen: Login },
CreateAccount: { screen: CreateAccount },
Chat: { screen: Chat },
TelaTeste: TelaTeste
});
export default createAppContainer(AppNavigator);
Change, to use arrow function, this inside user() refers to a different thing
get user() {
return {
name: this.props.navigation.state.params.name,
email: this.props.navigation.state.params.email,
avatar: this.props.navigation.state.params.avatar,
id: firebaseSvc.uid,
_id: firebaseSvc.uid // need for gifted-chat
};
}
to
user = () => {
return {
name: this.props.navigation.state.params.name,
email: this.props.navigation.state.params.email,
avatar: this.props.navigation.state.params.avatar,
id: firebaseSvc.uid,
_id: firebaseSvc.uid // need for gifted-chat
};
}
I have this chat screen in my app where I am sending a message with the help of a button next to it and with its onPress(),
Here is the code:
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
TextInput,
Button,
Image,
TouchableOpacity,
Picker,
AsyncStorage
} from "react-native";
import axios from "axios";
import { Dropdown } from "react-native-material-dropdown";
import { Input } from "native-base";
class MessageForm extends Component {
state = {
message: "",
rc_id: this.props.rc_id,
usertype: this.props.usertype,
senderid: this.props.userid,
subject: this.props.subject
};
sendMessage = async () => {
console.log(
this.state.rc_id,
this.state.usertype,
this.state.senderid,
this.state.message,
this.state.subject
);
try {
let { data } = await axios
.post("https://tgesconnect.org/api/Communicate_class", {
userid: this.state.rc_id,
usertype: this.state.usertype,
message: this.state.message,
senderid: this.state.senderid,
subject: this.state.subject
})
.then(response => {
console.log(response.data);
this.setState({
message: ""
});
});
} catch (err) {
console.log(err);
}
};
render() {
return (
<View>
<View style={styles.container}>
<Input
style={styles.textInput}
placeholder={this.props.message}
underlineColorAndroid="transparent"
onChangeText={message => {
this.setState({ message });
}}
/>
<TouchableOpacity
style={styles.button}
onPress={() => {
this.sendMessage();
}}
>
<Image source={require("../../Assets/Images/ic_send.png")} />
</TouchableOpacity>
</View>
</View>
);
}
}
export default MessageForm;
const styles = StyleSheet.create({
container: {
display: "flex",
flexDirection: "row",
minWidth: "100%",
backgroundColor: "#eeeeee",
borderTopColor: "#cccccc",
borderTopWidth: 1,
flex: 1,
justifyContent: "flex-end"
},
textInput: {
flex: 1,
backgroundColor: "#ffffff",
height: 40,
margin: 10,
borderRadius: 5,
padding: 3
},
button: {
flexShrink: 0,
width: 40,
height: 40,
marginTop: 10,
marginRight: 10,
marginBottom: 10,
alignItems: "center",
justifyContent: "center"
},
container1: {
flex: 1,
alignItems: "center",
justifyContent: "center"
}
});
Now when I click on the Touchable icon, the textbox is not getting cleared, I don't understand why it is not happening.
I have changed the state again to have a blank text but still it is not happening.
Bind the input value with the state.
<Input
style={styles.textInput}
placeholder={this.props.message}
underlineColorAndroid="transparent"
onChangeText={message => {this.setState({ message });}}
value={this.state.message}
/>
You can use useState.
just import by import {useState} from "react";
const [text, setText] = useState("");
const onChange = (textValue) => setText(textValue);
return (
<View style={styles.container}>
<TextInput
placeholder="Item"
style={styles.text}
onChangeText={onChange}
value={text}
/>
<TouchableOpacity
style={styles.btn}
onPress={() => {
//addItem.addItem(text);
setText("");
}}
>
<Text>Add</Text>
</TouchableOpacity>
</View>
);
<TextInput
style={styles.textInput}
placeholder="Start to type.."
multiline={true}
maxLength={3000}
value={this.state.sms}
onChangeText={(sms)=>this.setState({sms})}
/>