App loads and Authentication form shows
android emulator showing error
Hi , so i'm a newbie to React and i'm following this Udemy course .. when i try to run, my app is loaded and it renders the Authentication form like a charm with no errors or warnings.
but once i try to sign in , once i hit the Login button : the scary Red Screen pops up .
i went through all the similar subjects , but none of them seem to fix my error .. i cant even get what exactly is wrong here
Here's my LoginForm.js :
import { connect } from 'react-redux';
import React, { Component } from 'react';
import { Card, CardSection, Input, Button } from './common';
import { emailChanged, passwordChanged, loginUser } from '../actions';
class LoginForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
}
onPasswordChange(text) {
this.props.passwordChanged(text);
}
onButtonPress() {
const { email, password } = this.props;
this.props.loginUser({ email, password });
}
render() {
return (
<Card>
<CardSection>
<Input
label="Email"
placeholder="votre email ici"
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
/>
</CardSection>
<CardSection>
<Input
secureTextEntry
label="mot de passe"
placeholder="mot de passe"
onChangeText={this.onPasswordChange.bind(this)}
value={this.props.password}
/>
</CardSection>
<CardSection>
<Button onPress={this.onButtonPress.bind(this)}>
Login
</Button>
</CardSection>
</Card>
);
}
}
const mapStateToProps = (state) => {
return {
email: state.auth.email,
password: state.auth.password
};
};
export default connect(mapStateToProps, { emailChanged, passwordChanged,
loginUser })(LoginForm);
Here's my actions creator :
import firebase from 'firebase';
import {
EMAIL_CHANGED,
PASSWORD_CHANGED,
LOGIN_USER_SUCCESS
} from './types';
export const emailChanged = (text) => {
return {
type: EMAIL_CHANGED,
paymoad: text
};
};
export const passwordChanged = (text) => {
return {
type: PASSWORD_CHANGED,
payload: text
};
};
export const loginUser = ({ email, password }) => {
return (dispatch) => {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => {
dispatch({ type: LOGIN_USER_SUCCESS, payload: user });
});
};
};
In the emailChanged action, you are using the wrong key for the payload. Instead of using payload you are using paymoad
With this you are not updating the store and the value for the email is not valid.
Related
Hello i am new to programming, and i have learn to use MERN to make a sign up,i have no issue with backend but when i tried to use redux ,i have this problem in the frontend
enter image description here
This is the code for the SignInScreen.js
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Link, useLocation, useNavigate } from 'react-router-dom'
import { login } from '../actions/userAction'
export const SignInScreen = (props, history) => {
const navigate = useNavigate
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const submitHandler = (e) => {
e.preventDefault()
dispatch(login(email, password))
}
const { search } = useLocation()
const redirectInUrl = new URLSearchParams(search).get('redirect')
const redirect = redirectInUrl ? redirectInUrl : '/'
const userlogin = useSelector((state) => state.userlogin)
const { userInfo, loading, error } = userlogin
const dispatch = useDispatch()
useEffect(() => {
if (userInfo) {
navigate(redirect)
}
}, [navigate, userInfo, redirect])
I dont know what wrong with the code,but i do know that it connected with the redux store which have reducer,action and constant..this is for the redux store.js
import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import {
userLoginReducer,
} from './reducers/userReducer'
const userInfo = localStorage.getItem('userInfo')
? JSON.parse(localStorage.getItem('userInfo'))
: null
const initialState = {
userLogin: { userInfo },
}
const reducer = combineReducers({
userLogin: userLoginReducer,
})
const middleware = [thunk]
const store = createStore(
reducer,
initialState,
compose(applyMiddleware(...middleware))
)
export default store
This is for constant
export const USER_LOGIN_REQUEST = 'USER_LOGIN_REQUEST'
export const USER_LOGIN_SUCCESS = 'USER_LOGIN_SUCCESS'
export const USER_LOGIN_FAIL = 'USER_LOGIN_FAIL'
export const USER_LOGOUT = 'USER_LOGOUT'
this is userReducer.js
import {
USER_LOGIN_REQUEST,
USER_LOGIN_SUCCESS,
USER_LOGIN_FAIL,
USER_LOGOUT,
} from '../constants/userConstant'
function userLoginReducer(state = {}, action) {
switch (action.type) {
case USER_LOGIN_REQUEST:
return { loading: true }
case USER_LOGIN_SUCCESS:
return { loading: false, userInfo: action.payload }
case USER_LOGIN_FAIL:
return { loading: false, error: action.payload }
case USER_LOGOUT:
return {}
default:
return state
}
}
export userLoginReducer
and lastly for user.js
import Axios from 'axios'
import {
USER_LOGIN_REQUEST,
USER_LOGIN_SUCCESS,
USER_LOGIN_FAIL,
} from '../constants/userConstant'
const login = (email, password) => async (dispatch) => {
try {
dispatch({ type: USER_LOGIN_REQUEST })
const config = { headers: { 'Content-Type': 'application/json' } }
const { data } = await Axios.post(
'/api/users/login',
{ email, password },
config
)
dispatch({ type: USER_LOGIN_SUCCESS, payload: data })
localStorage.setItem('userInfo', JSON.stringify(data))
} catch (error) {
dispatch({
type: USER_LOGIN_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
})
}
}
export login
I just want to get the data into the userInfo but it dont recognized them and said it is a TypeError..I hope u can help me with this..im using the redux latest version
The problem is in userLoginReducer. Each reducer should return a complete new copy of the store.
If you return just the changes, the object you return replaces the entire state.
For example in this code:
switch (action.type) {
case USER_LOGIN_REQUEST:
return { loading: true };
}
The state { userLogin: { userInfo } } will be replaced with { loading: true }. Then you will not have userLogin anymore in the state. That's why you get the error.
To overcome this problem, spread the previous state in returned object (for all actions):
switch (action.type) {
case USER_LOGIN_REQUEST:
return { ....state, loading: true }; // ...state copies exist state to the new copy of state
}
Note: To easily solve similar bugs in the future, I recommend to use redux devtools extension. It is a great extension for debugging and look at changes in redux store.
I have tried that but still cannot fix my problem,this is the rest of my signinScreen,js
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Link, useLocation, useNavigate } from 'react-router-dom'
import { login } from '../actions/userAction'
export const SignInScreen = (props, history) => {
const navigate = useNavigate
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const submitHandler = (e) => {
e.preventDefault()
dispatch(login(email, password))
}
const { search } = useLocation()
const redirectInUrl = new URLSearchParams(search).get('redirect')
const redirect = redirectInUrl ? redirectInUrl : '/'
const userlogin = useSelector((state) => state.userlogin)
const { userInfo, loading, error } = userlogin
const dispatch = useDispatch()
useEffect(() => {
if (userInfo) {
navigate(redirect)
}
}, [navigate, userInfo, redirect])
return (
<Container className="small-container">
<h1 className="my-3">Sign In</h1>
<Form onSubmit={submitHandler}>
<Form.Group className="mb-3" controlId="email">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
required
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
required
onChange={(e) => setPassword(e.target.value)}
/>
</Form.Group>
<div className="mb-3">
<Button type="submit">Sign In</Button>
</div>
<div className="mb-3">
New Customer?{' '}
<Link to={`/signup?redirect=${redirect}`}>Create new account</Link>
</div>
</Form>
</Container>
)
}
it still show the same error like before,i have no idea to solve this
How do I set state to that of my payload? I would like my global state to have the recent changes, not the payload. Please could someone explain why/how this is happening? Do I need to create another reducer/effect to set the state? I want to set this state as global within the app. I would greatly appreciate it.
I am using the following:
Firebase Firestore
Rematch for Redux
React Native
This is My debugger (image).
Result of the code below.
Here is my code:
Index.js
import { init } from '#rematch/core'
import user from './user'
const models = {
user,
}
const store = init({
models,
})
export default { getState, dispatch } = store
Model.js (User.js)
import firebase from 'firebase';
import db from '../config/firebase'
const user = {
state: {},
reducers: {
login(userData) {
return userData
},
email(state, email) {
return { ...state, email }
},
password(state, password) {
return { ...state, password }
},
username(state, username) {
return { ...state, username }
},
fullname(state, fullname) {
return { ...state, fullname }
},
},
effects: () => ({
async signup() {
const { email, password, username, fullname } = getState().user
const response = await firebase.auth().createUserWithEmailAndPassword(email, password)
if (response.user.uid) {
const userData = {
uid: response.user.uid,
email: email,
username: username,
fullname: fullname,
bio: 'test',
gender: 'teste',
phoneNum: 'teste',
profilePic: 'te',
status: 'teste',
}
db.collection('users').doc(response.user.uid).set(userData)
alert(userData.uid)
return dispatch.user.login(userData)
}
}
})
}
export default user
SignUp.js
import * as React from 'react';
import {
TextInput,
Text,
KeyboardAvoidingView,
SafeAreaView,
TouchableOpacity,
Alert,
}
from 'react-native';
import styles from '../styles'
import { connect } from 'react-redux';
import '#expo/vector-icons';
import 'redux';
class Signup extends React.Component {
onPress = () => {
this.props.SignUp()
this.props.navigation.navigate('Home')
}
render() {
const { routeName } = this.props.navigation.state
return (
<SafeAreaView style={styles.container}>
<KeyboardAvoidingView behavior='position'>
<Text style={styles.mainText}>
EMAIL
</Text>
<TextInput
style={styles.inputText}
editable={routeName === 'Signup' ? true : false}
value={this.props.user.email}
onChangeText={input => this.props.setEmail(input)}
/>
<Text style={styles.mainText}>
PASSWORD
</Text>
<TextInput
style={styles.inputText}
editable={routeName === 'Signup' ? true : false}
value={this.props.user.password}
onChangeText={input => this.props.setPassword(input)}
secureTextEntry={true}
/>
<Text style={styles.mainText}>
USERNAME
</Text>
<TextInput
style={styles.inputText}
value={this.props.user.username}
onChangeText={input => this.props.setUserName(input)}
/>
<Text style={styles.mainText}>
FULL NAME
</Text>
<TextInput
style={styles.inputText}
value={this.props.user.fullname}
onChangeText={input => this.props.setFullName(input)}
/>
<TouchableOpacity
style={styles.buttonLighGray}
onPress={() => this.onPress()}>
<Text style={styles.buttonDarkText}>
Accept & Sign Up
</Text>
</TouchableOpacity>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
}
const mapState = (state) => ({
user: state.user,
})
const mapDispatch = (dispatch) => ({
setEmail: mail => dispatch.user.email(mail),
setPassword: pass => dispatch.user.password(pass),
setUserName: usern => dispatch.user.username(usern),
setFullName: fulln => dispatch.user.fullname(fulln),
SignUp: () => dispatch.user.signup(),
})
export default connect(mapState, mapDispatch)(Signup)
Screen.js
import * as React from 'react';
import {
View,
TextInput,
Alert,
Text,
KeyboardAvoidingView,
SafeAreaView,
TouchableOpacity,
}
from 'react-native';
import styles from '../styles'
import { connect } from 'react-redux';
import { Image } from 'react-native-elements';
import '#expo/vector-icons';
import 'redux';
import firebase from 'firebase'
class Screen extends React.Component {
render() {
return (
<SafeAreaView style={styles.container}>
<Text> Full Name: {this.props.user.fullName}</Text>
<Text> Email: {this.props.user.email}</Text>
<Text> username: {this.props.user.username}</Text>
<Text> bio: {this.props.user.bio}</Text>
<Text> gender: {this.props.user.gender}</Text>
<Text> phoneNum: {this.props.user.phoneNum}</Text>
<Text> profilePic: {this.props.user.profilePic}</Text>
</SafeAreaView>
);
}
}
const mapState = (state) => ({
user: state.user,
})
const mapDispatch = (dispatch) => ({
setEmail: mail => dispatch.user.email(mail),
setPassword: pass => dispatch.user.password(pass),
setUserName: usern => dispatch.user.username(usern),
setFullName: fulln => dispatch.user.fullname(fulln),
})
export default connect(mapState, mapDispatch)(Screen)
The problem is that you are returning the current state again in the login reducer. (you declared is at user data)
login(state, payload) {
return {
...state,
...payload
}
// this will take the global state and overwrite everything that is in payload (merge both objects
},
else you could just do just return payload but this could overwrite other stored values in the future!
I'm trying to login using firebase and redux in react native. But It is giving error "The email address is badly formatted." If I dismiss the error and still give email and password, it gives error saying "The password is invalid or the user does not have a password". What might be the problem here?
If the firebase part is removed, the app works perfectly. The inputs works as usual.
Have a look at the video here
Code:
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import reduxThunk from 'redux-thunk';
import reducers from './src/reducers';
import LoginForm from './src/components/LoginForm';
import firebase from '#firebase/app';
import '#firebase/auth';
export default class App extends Component<Props> {
componentWillMount() {
const config = {
apiKey: 'xxxxxxxxxxxxxxx',
authDomain: 'xxxxxxxxxxxxxxx',
databaseURL: 'xxxxxxxxxxxxxxx',
storageBucket: 'xxxxxxxxxxxxxxx',
messagingSenderId: 'xxxxxxxxxxxxxxx'
};
firebase.initializeApp(config);
}
render() {
return (
<Provider store={createStore(reducers, {}, applyMiddleware(reduxThunk))}>
<LoginForm />
</Provider>
);
}
}
Action creators
import firebase from 'firebase';
import { EMAIL_CHANGED, PASSWORD_CHANGED, LOGIN_USER_SUCCESS } from './types';
export const emailChanged = (text) => {
return {
type: EMAIL_CHANGED,
payload: text
};
};
export const passwordChanged = (text) => {
return {
type: PASSWORD_CHANGED,
payload: text
};
};
export const loginUser = ({ email, password }) => {
return (dispatch) => {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => {
dispatch({ type: 'LOGIN_USER_SUCCESS', payload: user });
});
};
};
LoginForm.js
import React, { Component } from 'react';
import { } from 'react-native';
import { connect } from 'react-redux';
import { Input, Button, Card, CardSection } from './common';
import { emailChanged, passwordChanged, loginUser } from '../actions';
import firebase from '#firebase/app';
import '#firebase/auth';
type Props = {};
class LoginForm extends Component<Props> {
onEmailChangeText = (text) => {
this.props.emailChanged(text);
}
onPasswordChangeText = (text) => {
this.props.passwordChanged(text);
}
onButtonPress = () => {
const { email, password } = this.props;
this.props.loginUser({ email, password });
}
render() {
return (
<Card>
<CardSection>
<Input
label='Email'
placeholder='email#gmail.com'
onChangeText={(text) => this.onEmailChangeText(text)}
value={this.props.email}
/>
</CardSection>
<CardSection>
<Input
label='Password'
placeholder='Password'
secureTextEntry
onChangeText={(text) => this.onPasswordChangeText(text)}
value={this.props.password}
/>
</CardSection>
<CardSection>
<Button onPress={this.onButtonPress()}>
Login
</Button>
</CardSection>
</Card>
);
}
}
const mapStateToProps = (state) => {
console.log('mapStateToProps', state.auth);
return { email: state.auth.email, password: state.auth.password, delete: state.auth.delete };
};
export default connect(mapStateToProps,
{ emailChanged, passwordChanged, loginUser })(LoginForm);
Reducer:
import { EMAIL_CHANGED, PASSWORD_CHANGED } from '../actions/types';
const INITIAL_STATE = { email: '', password: '', delete: '' };
export default (state = INITIAL_STATE, action) => {
console.log('emailReducer', state);
switch (action.type) {
case EMAIL_CHANGED:
return { ...state, email: action.payload };
case PASSWORD_CHANGED:
return { ...state, password: action.payload };
default:
return state;
}
};
I'm recently practicing React Native with Redux and developing a login form attached to Firebase. The thing is, whenever the signin button is clicked it should give an error above button "authentication failed".
But whenever I tried to click the button, it gives an error: "signinwithemailandpassword failed first argument email must be a valid string".
I've tried hours to solve this but couldn't get the answer.
Here is my code:
LOGINFORM:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { CardSection, Card, Input, Button } from './common';
import { emailChanged, passwordChanged, loginUser } from '../actions';
import { connect } from 'react-redux';
class LoginForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
//Its like setState to action, the text is send as a parameter to our action.
}
onPasswordChange(text){
this.props.passwordChanged(text);
}
onButtonPress(){
this.props.loginUser( this.props.email, this.props.password );
}
renderError(){
if (this.props.error){
<View style={{ backgroundColor: 'white' }}>
<Text style={ Styles.errorTextStyle }>
{this.props.error}
</Text>
</View>
}
}
render() {
return(
<Card>
<CardSection>
<Input
label='Email'
placeHolder='email#gmail.com'
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
//What is this function bind to?
//Actually, this bind function has a 'this' keyword and 'this' keyword is actually a
//parameter that is send to the onEmailChange, 'this' is recieved by 'text' param as the
//text written in the email field so its binded and called whenever user writes anything
//in the field of email.
//We're using 'this' onEmailChange is a call me back (callback) function that will invoke
//when input is pressed or not pressed, that is why we're using bind.
/>
</CardSection>
<CardSection>
<Input
secureTextEntry
label='Password'
placeHolder='password'
onChangeText={this.onPasswordChange.bind(this)}
value={this.props.password}
/>
</CardSection>
{this.renderError()}
<CardSection>
<Button onPress={this.onButtonPress.bind(this)}> Login </Button>
</CardSection>
</Card>
);
}
}
const Styles = {
errorTextStyle: {
fontSize: 20,
alignSelf: 'center',
color: 'red'
}
}
const mapStateToProps = (state) => {
return {
email: state.auth.email,
password: state.auth.password,
error: state.auth.error
};
console.log(state.auth.email);
};
export default connect(mapStateToProps, { emailChanged, passwordChanged, loginUser })(LoginForm);
//since we connect and added { emailChanged } as action, now we can access this.props.emailChanged.
ACTION INDEX FILE:
import firebase from 'firebase';
import { EMAIL_CHANGED, PASSWORD_CHANGED, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL } from './types';
export const emailChanged = (text) => {
return{
type: EMAIL_CHANGED,
payload: text
};
}
export const passwordChanged = (text) => {
return {
type: PASSWORD_CHANGED,
payload: text
};
}
export const loginUser = ({ email, password }) => {
return(dispatch) => {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(() => loginUserFail(dispatch));
});
};
};
const loginUserFail = (dispatch) => {
dispatch({ type: LOGIN_USER_FAIL });
};
const loginUserSuccess = (dispatch, user) => {
dispatch({ type: LOGIN_USER_SUCCESS, payload: user });
};
AUTH REDUCER:
import { EMAIL_CHANGED, PASSWORD_CHANGED, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL } from '../actions/types';
const INITIAL_STATE = { email: '', password: '', user: null, error: '' };
export default (state = INITIAL_STATE, action) => {
//switch statement in Reducer
switch (action.type) {
case EMAIL_CHANGED:
return { ...state, email: action.payload };
case PASSWORD_CHANGED:
return { ...state, password: action.payload };
case LOGIN_USER_SUCCESS:
return { ...state, user: action.payload };
case LOGIN_USER_FAIL:
return { ...state, error: 'Authentication failed.' };
default:
return state;
}
};
APP.JS
import React, {Component} from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import firebase from 'firebase';
import ReduxThunk from 'redux-thunk';
import reducers from './reducers';
import LoginForm from './components/LoginForm'
class App extends Component {
componentWillMount() {
var config = {
apiKey: 'AIzaSyAjHwCvftP1w0nKJTylUQcXAH-rThhZ6sQ',
authDomain: 'bold-circuit-429.firebaseapp.com',
databaseURL: 'https://bold-circuit-429.firebaseio.com',
projectId: 'bold-circuit-429',
storageBucket: 'bold-circuit-429.appspot.com',
messagingSenderId: '270696683683'
};
firebase.initializeApp(config);
}
render(){
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return(
<Provider store={store}>
<LoginForm />
</Provider>
);
}
}
export default App;
It looks like the problem is your connect() function call in LOGINFORM.
I pull out your { emailChanged, passwordChanged, loginUser } argument you're passing to connect() and change it to this:
const mapStateToProps = (state) => {
return {
email: state.auth.email,
password: state.auth.password,
error: state.auth.error
};
console.log(state.auth.email);
};
const mapDispatchToProps = (dispatch) => {
return {
emailChanged: (emailAddress) => dispatch(emailChanged(emailAddress),
passwordChanged: (password) => dispatch(passwordChanged(password)),
loginUser: (email, password) => dispatch(loginUser(email, password))
}
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
Your initial attempt used object decomposition to create an object to pass to connect. That object ended up looking like
{
emailChanged: emailChanged,
passwordChanged: passwordChanged,
loginUser: loginUser
}
My function will take a dispatch argument and map those three values of props (emailChanged, passwordChanged, loginUser) to functions that dispatch the action to your reducers.
EDIT: Your full LOGINFORM.js file should look like this:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { CardSection, Card, Input, Button } from './common';
import { emailChanged, passwordChanged, loginUser } from '../actions';
import { connect } from 'react-redux';
class LoginForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
//Its like setState to action, the text is send as a parameter to our action.
}
onPasswordChange(text){
this.props.passwordChanged(text);
}
onButtonPress(){
this.props.loginUser( this.props.email, this.props.password );
}
renderError(){
if (this.props.error){
<View style={{ backgroundColor: 'white' }}>
<Text style={ Styles.errorTextStyle }>
{this.props.error}
</Text>
</View>
}
}
render() {
return(
<Card>
<CardSection>
<Input
label='Email'
placeHolder='email#gmail.com'
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
//What is this function bind to?
//Actually, this bind function has a 'this' keyword and 'this' keyword is actually a
//parameter that is send to the onEmailChange, 'this' is recieved by 'text' param as the
//text written in the email field so its binded and called whenever user writes anything
//in the field of email.
//We're using 'this' onEmailChange is a call me back (callback) function that will invoke
//when input is pressed or not pressed, that is why we're using bind.
/>
</CardSection>
<CardSection>
<Input
secureTextEntry
label='Password'
placeHolder='password'
onChangeText={this.onPasswordChange.bind(this)}
value={this.props.password}
/>
</CardSection>
{this.renderError()}
<CardSection>
<Button onPress={this.onButtonPress.bind(this)}> Login </Button>
</CardSection>
</Card>
);
}
}
const Styles = {
errorTextStyle: {
fontSize: 20,
alignSelf: 'center',
color: 'red'
}
}
const mapStateToProps = (state) => {
return {
email: state.auth.email,
password: state.auth.password,
error: state.auth.error
};
console.log(state.auth.email);
};
const mapDispatchToProps = (dispatch) => {
return {
emailChanged: (emailAddress) => dispatch(emailChanged(emailAddress),
passwordChanged: (password) => dispatch(passwordChanged(password)),
loginUser: (email, password) => dispatch(loginUser(email, password))
}
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
//since we connect and added { emailChanged } as action, now we can access this.props.emailChanged.
onButtonPress(){
this.props.loginUser( this.props.email, this.props.password );
}
wrong call LoginUser function
onButtonPress(){
this.props.loginUser({ this.props.email, this.props.password });
}
the code is working and app also showing on mobile but the problem is that the authentication is always failed even i entered the correct email/pass.
this authAction.js file.
import firebase from 'firebase';
import { LOGIN_USER_FAIL, EMAIL_CHANGED , PASSWORD_CHANGED , LOGIN_USER_SUCCESS, LOGIN_USER } from './types';
import { Actions } from 'react-native-router-flux';
//here define the actionCreator of email
export const emailChanged = (text) => {
return {
//type of action defined in type.js file
type: 'EMAIL_CHANGED',
payload: text
};
};
//here define the actionCreator of password
export const passwordChanged = (text) => {
return {
//type of action defined in type.js file
type: 'PASSWORD_CHANGED',
payload: text
};
};
export const loginUser = ({ email, password}) => {
return (dispatch) => {
dispatch({type: LOGIN_USER});
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch( () => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user) )
.catch(() => loginUserFail(dispatch));
});
};
};
const loginUserFail = (dispatch) => {
dispatch({type: LOGIN_USER_FAIL});
Actions.main();
};
const loginUserSuccess = ( dispatch, user) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user
});
};
this is types.js file where i stored all the strings in variables
export const EMAIL_CHANGED = 'email_changed';
export const PASSWORD_CHANGED = 'password_changed';
export const LOGIN_USER_SUCCESS = 'login_user_success';
export const LOGIN_USER_FAIL = 'login_user_fail';
export const LOGIN_USER = 'login_user';
this is authReducer.js file
import { EMAIL_CHANGED , PASSWORD_CHANGED, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL, LOGIN_USER } from '../actions/types';
const INITIAL_STATE = { email: '', password: '', user: null, error: '', loading: false };
export default (state= INITIAL_STATE, action) => {
switch(action.type){
//..state isto update the state object
case EMAIL_CHANGED:
return { ...state, email: action.payload};
case PASSWORD_CHANGED:
return { ...state, password: action.payload };
case LOGIN_USER_SUCCESS:
return { ...state, user : action.payload, error:'', loading: false};
case LOGIN_USER_FAIL:
return { ...state, error: 'Authentication Failed', password: '', loading: false };
case LOGIN_USER:
return { ...state, loading: true, error: '' };
default:
return state;
}
};
this is app.js file where i inserted the firebase API
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
import firebase from 'firebase'
import rootReducer from './reducers';
import LoginForm from './components/LoginForm';
class App extends Component {
componentWillMount() {
firebase.initializeApp({
apiKey: 'AIzaSyAe45P2xc8q09gpEV6oA6s4U9YjnaTf9vc',
authDomain: 'manager-6cde7.firebaseapp.com',
databaseURL: 'https://manager-6cde7.firebaseio.com',
projectId: 'manager-6cde7',
storageBucket: 'manager-6cde7.appspot.com',
messagingSenderId: '408722531799'
});
}
render()
{
const store = createStore(rootReducer,applyMiddleware(thunk));
return(
<Provider store={store} >
<LoginForm />
</Provider>
);
}
}
export default App;
this is loginForm.js file.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { emailChanged, passwordChanged, loginUser } from '../actions';
import { Button, Card, CardSection, Input, Spinner } from './common';
import { Text } from 'react-native';
class LoginForm extends Component {
onEmailChange(text){
//now call the actionCreator in actions index.js
this.props.emailChanged(text);
}
onPasswordChanged(text){
//now call the actionCreator in actions index.js
this.props.passwordChanged(text);
}
onButtonPress() {
const {email, password} = this.props;
this.props.loginUser({email, password});
}
renderButton(){
if(this.props.loading)
{
return <Spinner size="large" />;
}
return (
<Button onPress={this.onButtonPress.bind(this)} >LogIn</Button>
);
}
render(){
return(
<Card>
<CardSection>
<Input
onChangeText={this.onEmailChange.bind(this)}
label="Email"
placeholder="email#gmail.com"
value={this.props.email}
/>
</CardSection>
<CardSection>
<Input
value={this.props.password}
onChangeText={this.onPasswordChanged.bind(this)}
secureTextEntry
label="Password"
placeholder="******"
/>
</CardSection>
<Text style={styles.errorAuthentication}>{this.props.error}</Text>
<CardSection>
{this.renderButton()}
</CardSection>
</Card>
);
}
}
const mapStateToProps = ({auth}) => {
const { email, password, error, loading } = auth;
return {
email, password, error, loading };
};
const styles = {
errorAuthentication: {
fontSize: 20,
color: 'red',
alignSelf: 'center'
}
};
export default connect(mapStateToProps, { emailChanged, passwordChanged, loginUser })(LoginForm);