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

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!

Related

Rendering Firebase data into FlatList

I am using React Native, Rematch for Redux and Firebase Firestore. I am attempting to pull data from my Firebase database and populate it inside my FlatList. The problem is, it is not giving me any error and it giving me a blank white screen. I do not know where I am going wrong.
This is what my database looks like - list of activities
This is what my Rematch for Redux store looks like:
import firebase from 'firebase';
import db from '../config/firebase'
const activity = {
state: {},
reducers: {
activities(state, payload) {
return {
...state,
...payload
}
},
},
effects: {
async getActivities() {
try {
const response = await db.collection('activities').get()
//console.log(response.docs.map(doc => doc.data()))
return dispatch({ type: 'activity/activities', payload: response.docs.map(doc => doc.data()) })
} catch (err) {
alert(err)
}
},
}
}
export default activity
Here is the component where I am using the FlatList:
import * as React from 'react';
import {
Text,
TouchableOpacity,
View,
FlatList,
ImageBackground
}
from 'react-native';
import styles from '../styles'
import { connect } from 'react-redux';
import '#expo/vector-icons';
import 'redux';
class Activities extends React.Component {
state = {
movetoArray: [],
outputActivity: [],
};
async componentDidMount() {
const activities = await this.props.getActivities()
this.state.movetoArray = Object.values(activities)
this.state.outputActivity = Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] }));
//this.state.arrayActivity = Object.entries(activities).map(item => ({...item[1], key: item[0]}));
console.log(this.state.outputActivity)
}
_renderItem = ({ item }) => (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('activitiesMD',
{
title: item.name,
objectData: item.data
})}>
<ImageBackground source={item.image} style={styles.inputTiles} imageStyle={{ borderRadius: 10 }}>
<View style={styles.inputTileTextView}>
<Text style={[styles.inputTileText, { color: item.colour }]}>{item.name}</Text>
</View>
</ImageBackground>
</TouchableOpacity>
);
render() {
const { routeName } = this.props.navigation.state
return (
<View style={styles.container}>
<FlatList
data={this.state.outputActivity}
keyExtractor={item => item.id}
renderItem={this._renderItem}
/>
</View>
);
}
}
const mapState = (state) => ({
activity: state.activity,
})
const mapDispatch = (dispatch) => ({
getActivities: () => dispatch.activity.getActivities(),
})
export default connect(mapState, mapDispatch)(Activities)
I do not know why I am getting this outcome. Please help me :)
If you directly mutate state in React then the component won't re-render. Please use this.setState({ ... }) like so:
- this.state.movetoArray = Object.values(activities)
- this.state.outputActivity = Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] }));
+ this.setState({ movetoArray: Object.values(activities), outputActivity: Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] })) })

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

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

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