The email address is badly formatted - react native, firebase and redux - firebase

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;
}
};

Related

useEffect hook problem, use redux to get data from backend to frontend

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

Rematch for Redux: Setting State to that of the Payload when Signing Up

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!

react navigation "navigate" function not working inside firebase Asynchronous login function

I'm following the famous tutorial of "the-complete-react-native-and-redux-course",
i'm implementing react-navigation with redux and firebase, my problem is that its using the obsolete "react-native-router-flux" approach, i tried to follow it, but the project is not building at all.
I tried to migrate it step by step the the official react-navigation, the problem is, when trying to navigate from inside Asynchronous function (like firebase login function), navigation is not working, (putting in mind that i'm using redux)
**Update: Solution found, below is working code:
here is my Asynchronous function code (inside actions.js):
import firebase from 'firebase';
import { NavigationActions } from 'react-navigation'
import {
EMAIL_CHANGED,
PASSWORD_CHANGED,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAIL,
LOGIN_USER
} 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}, NavigationActions) => {
return (dispatch) => {
//indicate start user log in process
dispatch({type: LOGIN_USER});
firebase.auth().signInWithEmailAndPassword(email,password)
.then(user => loginUserSuccess(dispatch, user, NavigationActions))
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user, NavigationActions))
.catch(() => loginUserFail(dispatch));
});
};
};
const loginUserFail = (dispatch) => {
dispatch({type: LOGIN_USER_FAIL});
}
const loginUserSuccess = (dispatch, user, NavigationActions) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user,
});
NavigationActions.navigate({ routeName: 'employeeList' })
};
and my router file:
import React from 'react';
import { StackNavigator } from 'react-navigation';
import LoginForm from './components/LoginForm';
import EmployeeList from './components/EmployeeList';
const Router = StackNavigator({
login: { screen: LoginForm },
employeeList: {screen: EmployeeList },
},
{
initialRouteName: 'login',
});
export default Router;
and App.js :
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
import firebase from 'firebase';
import ReduxThunk from 'redux-thunk';
//import LoginForm from './components/LoginForm';
import Router from './Router';
class App extends Component {
componentWillMount(){
const config = {
apiKey: "AIzaSyDV_vLg656D36E8T9GVraA6ZmZrcUi2QH4",
authDomain: "XXXXXXXXXX.firebaseapp.com",
databaseURL: "https://XXXXXXXXX.firebaseio.com",
projectId: "manager-ba44d",
storageBucket: "manager-ba44d.appspot.com",
messagingSenderId: "200262066369"
};
firebase.initializeApp(config);
}
render() {
const store= createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<Router />
</Provider>
);
}
}
export default App;
my login component that calls the Asynch function:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { connect } from 'react-redux';
import { emailChanged, passwordChanged, loginUser } from '../actions';
import { Card, CardSection, Input, Button, Spinner } from './common';
class LoginForm extends Component {
static navigationOptions = () => ({
title: 'Login screen',
headerTitleStyle: {
textAlign:"center",
flex:1
}
});
onEmailChange(text){
this.props.emailChanged(text);
}
onPasswordChange(text){
this.props.passwordChanged(text);
}
onButtonPress(){
const {email, password, navigation} = this.props;
this.props.loginUser({email, password}, navigation);
}
renderError(){
if(this.props.error){
return(
<View style={{backgroundColor: 'white'}}>
<Text style={styles.errorTextStyle}>
{this.props.error}
</Text>
</View>
)
}
}
renderButton(){
if(this.props.loading){
return <Spinner size="large" />;
}
return (
<Button
style={styles.buttonStyle}
buttonText="Login" onPress={this.onButtonPress.bind(this)}>
</Button>
);
}
render(){
return(
<Card>
<CardSection>
<Input
label="Email"
placeholder="email#gmail.com"
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
/>
</CardSection>
<CardSection>
<Input
secureTextEntry
label="password"
placeholder="password"
onChangeText={this.onPasswordChange.bind(this)}
value={this.props.password}
/>
</CardSection>
{this.renderError()}
<CardSection>
{this.renderButton()}
</CardSection>
</Card>
);
}
}
const mapStateToProps = state => {
return {
email: state.auth.email,
password: state.auth.password,
error: state.auth.error,
loading: state.auth.loading
};
};
export default connect(mapStateToProps,
{
emailChanged,
passwordChanged,
loginUser
})(LoginForm);
const styles = {
errorTextStyle: {
fontSize: 20,
alignSelf: 'center',
color: 'red'
},
buttonStyle:{
flex: 1,
flexDirection: 'row',
alignSelf: 'stretch'
}
}
UPDATE
You need to import NavigationActions like this
import { NavigationActions } from 'react-navigation'
export const loginUser = ({email, password}, navigation) => {
return (dispatch) => {
//indicate start user log in process
dispatch({type: LOGIN_USER});
firebase.auth().signInWithEmailAndPassword(email,password)
.then(user => loginUserSuccess(dispatch, user))
.then(NavigationActions.navigate('employeeList'))
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user, navigation))
.catch(() => loginUserFail(dispatch));
});
};
};
const loginUserFail = (dispatch) => {
dispatch({type: LOGIN_USER_FAIL});
}
const loginUserSuccess = (dispatch, user, navigation) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user,
});
NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'employeeList' })],
}),
};

signinwithemailandpassword failed first argument email must be a valid string

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 });
}

authentication is not working with firebase using react-native-redux + redux-thunk

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);

Resources