I'm currently working on an e-commerce project and we are using react-redux. But I'm having a problem with returning a response from API instances using Axios request call on the action for Login with Jwt module.
This is Axios file that consists of base URLs and instances.
api/lib/axios.js:
/* eslint-disable no-nested-ternary */
import axios from "axios"
import { store } from "../../redux/store"
import { REFRESH_TOKEN } from "../../redux/auth/constant"
import Environment from "./environment"
const axiosInstance = axios.create({
baseURL: Environment.BASE_URL,
headers: {
Authorization: localStorage.getItem("access")
? `JWT${localStorage.getItem("access")}`
: "none",
"Content-Type": "application/json",
accept: "application/json"
}
})
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
const originalRequest = error.config
if (
error.response.status === 401 &&
error.response.statusText === "Unauthorized"
) {
const body = store.getState().auth.token.refresh
return axiosInstance
.post("api/token/refresh/", { refresh: body })
.then((response) => {
store.dispatch({
type: REFRESH_TOKEN,
payload: response.data
})
axiosInstance.defaults.headers.Authorization = `JWT ${response.data.access}`
originalRequest.headers.Authorization = `JWT ${response.data.access}`
return axiosInstance(originalRequest)
})
}
return Promise.reject(error)
}
)
export default axiosInstance
Here is also an environment file where all our environment variables are stored.
api/lib/environment.js:
const Environment = {
BASE_URL: "http://babylandworld.com:8000/"
}
export default Environment
I'm calling an API request from auth file inside api/lib/auth as:
api/lib/auth.js:
/* eslint-disable import/prefer-default-export */
import axiosInstance from "./axios"
// Auth Request from backend api using axios
const auth = async (username, password) => {
const body = { username, password }
const response = await axiosInstance
.post(`/api/token/obtain/`, body)
.then((res) => {
axiosInstance.defaults.headers.Authorization = `JWT ${res.data.access}`
})
return response
}
export { auth }
I have dispatch the response from the api/auth.js file to auth/action.js. But I'm getting an error on dispatch and catch with no user data after submitting the login form.
Here is action.js code:
auth/action.js:
import * as constants from "./constant"
import { auth } from "../../api/lib/auth"
const loginBegin = () => ({
type: constants.LOGIN_BEGIN
})
const login = ({ username, password }) => (dispatch) => {
dispatch({
type: constants.LOGIN_SUCCESS,
paylaod: auth(username, password).data
}).catch(() =>
dispatch({
type: constants.LOGIN_FAIL
})
)
}
export { loginBegin, login }
Also, I have created actions types in constant.js file as:
auth/constant.js:
export const REFRESH_TOKEN = "REFRESH_TOKEN"
export const LOGIN_BEGIN = "LOGIN_BEGIN"
export const LOGIN_SUCCESS = "LOGIN_SUCCESS"
export const LOGIN_FAIL = "LOGIN_FAIL"
export const AUTH_ERROR = "AUTH_ERROR"
export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS"
Here is reducer file as:
auth/reducer.js:
import { actions } from "react-table"
import * as constants from "./constant"
const initialState = {
token: localStorage.getItem("token"),
isAuthenticated: null,
isLoading: false,
user: null
}
function authReducer(state = initialState, action) {
switch (action.type) {
case constants.LOGIN_BEGIN:
return {
...state,
isAuthenticated: false,
isLoading: true,
user: ""
}
case constants.LOGIN_SUCCESS:
return {
...state,
...action.payload,
isAuthenticated: true,
isLoading: false
}
case constants.LOGIN_FAIL:
case constants.LOGOUT_SUCCESS:
return {
...state,
token: null,
isAuthenticated: false,
user: null,
isLoading: false
}
default:
return state
}
}
export default authReducer
This is our login page component as:
pages/auth/loginTabset.js:
/* eslint-disable jsx-a11y/anchor-has-content */
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, { Component } from "react"
import PropTypes from "prop-types"
import { connect } from "react-redux"
import { Redirect } from "react-router-dom"
import { login } from "../../redux/auth/action"
export class LoginTabset extends Component {
state = {
username: "",
password: ""
}
clickActive = (event) => {
document.querySelector(".nav-link").classList.remove("show")
event.target.classList.add("show")
}
handleSubmit = (e) => {
e.preventDefault()
this.props.login(this.state.username, this.state.password)
}
handleChange = (e) => this.setState({ [e.target.name]: e.target.value })
render() {
if (this.props.isAuthenticated) {
return <Redirect to="/dashboard" />
}
const { username, password } = this.state
return (
<div>
<h4 className="text-center">Login Panel</h4>
<hr />
<form
className="form-horizontal auth-form"
onSubmit={this.handleSubmit}>
<div className="form-group">
<input
required=""
name="username"
value={username}
type="text"
className="form-control"
placeholder="Username"
id="username"
onChange={this.handleChange}
/>
</div>
<div className="form-group">
<input
required=""
name="password"
value={password}
type="password"
className="form-control"
placeholder="Password"
id="password"
onChange={this.handleChange}
/>
</div>
<div className="form-terms">
<div className="custom-control custom-checkbox mr-sm-2">
<input
type="checkbox"
className="custom-control-input"
id="customControlAutosizing"
/>
<label className="d-block" htmlFor="chk-ani2">
<input
className="checkbox_animated"
id="chk-ani2"
type="checkbox"
/>
Reminder Me{" "}
<span className="pull-right">
{" "}
<a href="#" className="btn btn-default forgot-pass p-0">
lost your password
</a>
</span>
</label>
</div>
</div>
<div className="form-button">
<button className="btn btn-primary" type="submit">
Login
</button>
</div>
<div className="form-footer">
<span>Or Login up with social platforms</span>
<ul className="social">
<li>
<a className="fa fa-facebook" href="" />
</li>
<li>
<a className="fa fa-twitter" href="" />
</li>
<li>
<a className="fa fa-instagram" href="" />
</li>
<li>
<a className="fa fa-pinterest" href="" />
</li>
</ul>
</div>
</form>
</div>
)
}
}
LoginTabset.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool.isRequired
}
const mapStateToProps = (state) => ({
isAuthenticated: state.auth.isAuthenticated
})
export default connect(mapStateToProps, { login })(LoginTabset)
Problem:
when submitting the login form, there is an error on dispatch an action from api/lib/auth and don't get any response data from the API server.
Please, anyone, help to solve this problem as soon as possible.
dispatch function doesn't return you a promise to use. You must instead call the auth function and wait on it before firing dispatch since it an async function.
You can use async-await with try catch like below
const login = ({ username, password }) =>async (dispatch) => {
try {
const res = await auth(username, password);
dispatch({
type: constants.LOGIN_SUCCESS,
paylaod: res.data,
})
} catch(error ) {
dispatch({
type: constants.LOGIN_FAIL
});
}
}
export { loginBegin, login }
Related
I am using Redux with ReactJS. I also am utilizing devise-JWT for auth. Upon a refresh of the page, my state is changed and loggedIn becomes "false". I also get 400 Bad Request error upon posting data through fetch. I can login just fine and be redirected.
My user reducer:
import {
SIGNUP_USER,
LOGIN_USER,
LOGOUT_USER,
STORE_TOKEN
} from '../actions/types'
const INITIAL_STATE = {
loggedIn: false,
currentUser: {}
}
export default (state = INITIAL_STATE, action) => {
switch(action.type){
case SIGNUP_USER:
return {
...state,
loggedIn: true,
currentUser: action.payload
}
case LOGIN_USER:
return {
...state,
loggedIn: true,
currentUser: action.payload
}
case LOGOUT_USER:
return {
...state,
user: state.users.filter(user => user.id !== action.payload.id),
loggedIn: false
}
case STORE_TOKEN:
return {
token: action.payload.token,
}
default:
return state
}
}
My action:
export function loginUser(data){
return (dispatch) => {
fetch("http://localhost:3000/login", {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: {
...data
}
})
})
.then(resp => {
//debugger
if (resp.ok) {
resp.json().then(json => {
localStorage.setItem('token', json.token)
dispatch({ type: LOGIN_USER, payload: json })
})
}
})
}
}
My login component:
import React from 'react'
import TextField from '#material-ui/core/TextField'
import Button from '#material-ui/core/Button'
import { loginUser } from '../actions/index'
import { connect } from 'react-redux'
class Login extends React.Component {
state = {
email: '',
password: ''
}
handleSubmit = (e) =>{
e.preventDefault()
let credentials = this.state
this.props.loginUser(credentials)
this.props.history.push('/bookmarks')
}
handleChange = (e) => {
this.setState({[e.target.name]: e.target.value})
}
render() {
const { email, password } = this.state
return (
<div className="login-form">
<h1>Login</h1>
<form onSubmit={this.handleSubmit}>
<div>
<TextField type="text" name="email" placeholder="Email" onChange={this.handleChange} value={email} />
</div>
<div>
<TextField type="password" name="password" placeholder="Password" onChange={this.handleChange} value={password}/>
</div><br></br>
<Button type="submit" value="Login">Login</Button>
</form>
</div>
)
}
}
const mapDispatch = (dispatch) => {
return {
loginUser: (credentials) => dispatch(loginUser(credentials))
}
}
export default connect(null, mapDispatch)(Login)
I used devise-JWT for authentication.
You're logged out because the only place you store the credentials is in the redux store, which is (essentially) a variable.
When you refresh the page, you reinitialise the store to the default state.
You haven't stored the credentials anywhere where they would persist, such as local storage or a cookie.
I have set everything in Redux side and I see every action in Redux Devtool. It works all perfect. The problem occurs when I want to dispatch action in React Component. In login component I want to dispatch action, wait its response then depending on response redirect it to a page or show errors. Here are my codes:
userActions.js
import axios from "axios";
import {
LOGIN_USER,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAILED,
} from "./types";
const loginUserRequest = () => {
return {
type: LOGIN_USER,
};
};
const loginUserSuccess = (user) => {
return {
type: LOGIN_USER_SUCCESS,
payload: user,
};
};
const loginUserFailed = (error) => {
return {
type: LOGIN_USER_FAILED,
payload: error,
};
};
export const loginUser = (dataSubmitted) => {
return (dispatch) => {
dispatch(loginUserRequest());
axios
.post("/api/users/login", dataSubmitted)
.then((response) => {
dispatch(loginUserSuccess(response.data));
})
.catch((err) => {
dispatch(loginUserFailed(err));
});
};
};
userReducer.js:
import {
LOGIN_USER,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAILED,
} from "../actions/types";
const initialState = {
loading: false,
user: "",
error: "",
};
export default function (state = initialState, action) {
switch (action.type) {
case LOGIN_USER:
return { ...state, loading: true };
case LOGIN_USER_SUCCESS:
return { ...state, loading: false, user: action.payload, error: "" };
case LOGIN_USER_FAILED:
return { ...state, loading: false, user: "", error: action.payload };
default:
return state;
}
}
The above codes works great and does the job. The problem is in following code where I am dispatching the async action. After I run the code I get this.props.userData as undefined.
Login.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { loginUser } from "../../actions/userActions";
export class Login extends Component {
state = {
email: "",
password: "",
errors: [],
};
displayErrors = (errors) =>
errors.map((error, i) => (
<div className="alert alert-danger" key={i}>
{error}
</div>
));
handleSubmit = (e) => {
e.preventDefault();
var { email, password } = this.state;
var errors = [];
if (email === "") {
errors.push("Email is required");
}
if (password === "") {
errors.push("Password is required");
}
this.setState({ errors: errors });
//Problem occurs here
this.props.dispatch(loginUser({ email, password }));
if (response.payload.success) {
sessionStorage.setItem("jwt", response.payload.token);
sessionStorage.setItem("userId", response.payload._id);
this.props.history.push("/");
} else {
errors.push("Username and/or Password is not correct");
this.setState({ errors: errors });
}
};
render() {
return (
<form className="form-signin" onSubmit={this.handleSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Sign in</h1>
{this.state.errors.length > 0 && this.displayErrors(this.state.errors)}
<label for="inputEmail" className="sr-only">
Email address
</label>
<input
type="email"
id="inputEmail"
className="form-control"
placeholder="Email address"
value={this.state.email}
onChange={(e) => {
this.setState({ email: e.target.value });
}}
required
autoFocus
/>
<label for="inputPassword" className="sr-only">
Password
</label>
<input
type="password"
id="inputPassword"
className="form-control"
placeholder="Password"
value={this.state.password}
onChange={(e) => {
this.setState({ password: e.target.value });
}}
required
/>
<div className="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" /> Remember me
</label>
</div>
<button
className="btn btn-lg btn-primary btn-block"
type="submit"
onClick={this.handleSubmit}
>
Sign in
</button>
<Link to="/register">Sign Up</Link>
</form>
);
}
}
function mapStateToProps(state) {
return {
userData: state.user,
};
}
export default connect(mapStateToProps)(Login);
You need to install connected-react-router to manipulate with a history inside redux:
import { push } from 'connected-react-router';
export const loginUser = (dataSubmitted) => {
return (dispatch) => {
dispatch(loginUserRequest());
axios
.post("/api/users/login", dataSubmitted)
.then((response) => {
dispatch(loginUserSuccess(response.data));
if (response.payload.success) {
sessionStorage.setItem("jwt", response.payload.token);
sessionStorage.setItem("userId", response.payload._id);
push("/");
} else {
errors.push("Username and/or Password is not correct");
}
})
.catch((err) => {
dispatch(loginUserFailed(err));
});
};
};
I am trying to make user login page with react and redux.
//loginAction.js
export function loginRequest(user){
return{
type: types.LOGIN_REQUEST,
user
}
}
export function loginSuccess(user){
return{
type: types.LOGIN_SUCCESS,
user
}
}
export function loginFailure(err){
return{
type: types.LOGIN_FAILURE,
err
}
}
export function login(username, password){
return function(dispatch) {
dispatch(loginRequest({ username }));
userApi.userLogin(username, password)
.then(
user => {
dispatch(loginSuccess(user));
},
err => {
dispatch(loginFailure(err.toString()))
}
)
}
}
//userReducer.js
const login = (state=initialState, action) => {
switch(action.types){
case types.LOGIN_SUCCESS:
case types.LOGIN_REQUEST:
return {
loggedIn: true,
user: action.user
}
case types.LOGIN_FAILURE:
return {}
default:
return state
}
};
LoginPage.js
import React, { useState, useEffect} from 'react';
import PropTypes from 'prop-types';
import {useDispatch, useSelector} from 'react-redux';
import {Redirect} from 'react-router-dom';
import {login} from '../redux/actions/loginAction'
const LoginPage = () => {
const [inputs, setInputs] = useState({
username: '',
password: ''
})
const [isauthenticated, setIsAuthenticated] = useState(false);
const { username, password } = inputs
const dispatch = useDispatch();
const loggingIn = useSelector(state => state.user);
const handleChange = (e) => {
const {name, value} = e.target;
setInputs(inputs =>({...inputs, [name]: value}))
}
const handleSubmit = (event) => {
event.preventDefault();
// setIsAuthenticated(true)
// this line needs to be improved
if( username && password ){
dispatch(login(username, password))
}
}
return(
<div className='field col-xs-5 col-lg-3'>
{
isAuthenticated ?
<Redirect to='/uploadfile' /> :
(
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={handleChange}
name="username"
label="username"
className="form-control"
placeholder="ID"
value={username}
/>
<input
type="password"
onChange={handleChange}
name="password"
label="password"
className="form-control"
placeholder="Password"
/>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
)
}
</div>
)
}
export default LoginPage;
Inside of LoginPage component, I have isAuthenticated state that I want to set true when its action returns 'LOGIN_SUCCESS', not always set true.
Is there a way to check it, like this?
const handleSubmit = (event) => {
event.preventDefault();
// setIsAuthenticated(true)
if( username && password ){
// can I do?
if(dispatch(login(username, password)) === 'types.LOGIN_SUCCESS'){
setIsAuthticated(true)
}
}
}
const login = (state=initialState, action) => {
switch(action.types){
case types.LOGIN_REQUEST:
return {
loggedIn: false,
user: null
}
case types.LOGIN_SUCCESS:
return {
loggedIn: true,
user: action.user
}
case types.LOGIN_FAILURE:
return {
loggedIn: false,
user: null
}
default:
return state
}
};
I would write it like that, you're not logged in before login_success. And inside loginform you should only check props - loggedIn and user.
I am trying pass logged data from my redux actions to the front end but keep getting user.name of null or undefined.
This is the front end where I am simply trying to get user.name to appear so that it says Hi user.name(name of persons account).
import React, { Component } from "react";
import { NewPropertyForm, FormPageOne, FormPageTwo, FormPageThree,
FormPageFour } from "../../components/NewPropertyForm";
import { PropertyList } from "../../components/PropertyList";
import { Container, Button, Modal, ModalCard, ModalCardTitle,
ModalBackground, ModalCardFooter, ModalCardHeader, Delete, ModalCardBody
} from 'bloomer';
import StepZilla from "react-stepzilla";
import modal from "./modal-bg.svg";
import "./Manager.css";
import {login} from '../../actions/authActions'
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux'
const steps =
[
{name: 'Step 1', component: <FormPageOne /> },
{name: 'Step 2', component: <FormPageTwo /> },
{name: 'Step 3', component: <FormPageThree /> },
{name: 'Step 4', component: <FormPageFour /> }
]
const modalBG = { backgroundImage: `url(${modal})` }
export class Manager extends Component {
// Setting our component's initial state
state = {
modal: "",
};
modalOpen = () => {
this.setState({ modal: "is-active" })
}
modalClose = () => {
this.setState({
modal: "",
login: "",
})
}
render() {
let { user } = this.props;
return (
<div className="manager">
<Container className="manager-container">
<div className="columns">
<div className="column">
<h1 className="title">Hi {user.name}</h1>
<h2 className="sub-title">You currently have 3 properties</h2>
<h2 className="sub-title">Check out the new applications you
received.</h2>
</div>
<div className="column user-dash-right">
<Button
isColor='primary'
className=""
onClick={this.modalOpen}><p>Create Listing</p></Button>
</div>
</div>
<h1 className="title has-text-centered">My Properties</h1>
<PropertyList />
<div className="new-property-modal">
<Modal className={this.state.modal}>
<ModalBackground />
<ModalCard style={ modalBG } >
<ModalCardBody>
<Delete onClick={this.modalClose} />
<div className='step-progress'>
<StepZilla
steps={steps}
showSteps={false}
nextButtonCls="button is-medium is-primary"
backButtonCls="button is-medium is-primary"
/>
</div>
</ModalCardBody>
</ModalCard>
</Modal>
</div>
</Container>
</div>
);
}
}
const mapStateToProps = ({auth}) => ({
user: auth.user,
authError: auth.authError
});
export default connect(mapStateToProps)(Manager)
This is the actions I have setup
import API from "../utils/API";
import { IS_AUTHENTICATED, AUTHENTICATION_FAILED } from
'../constants/actionTypes';
export const signup = ({name, email, phonenumber, password, role}) =>
async dispatch => {
try {
const {data} = await API.saveUser({
name,
email,
phonenumber,
password,
role
})
dispatch({
type: IS_AUTHENTICATED,
payload: data.user
})
console.log('--success', data);
} catch(error) {
console.error(error);
console.log('Come on work damnit')
}
}
export const login = ({email, password}) => async dispatch => {
try {
const {data} = await API.loginUser({
email,
password
})
dispatch({
type: IS_AUTHENTICATED,
payload: data.user
});
console.log('--success', data.user.name);
} catch(error) {
dispatch({
type: AUTHENTICATION_FAILED,
payload: "Invalid credentials, cannot login"
});
console.error(error);
}
}
export const getAuthenticated = () => async dispatch => {
try {
const {data, error} = await API.getAuthenticated();
console.log(data);
if(data) {
dispatch({
type: IS_AUTHENTICATED,
payload: data
});
} else {
console.log('ssss', error)
}
// if(getUser) login
//else logout
} catch(error) {
//window redirect to login
}
}
export const logout = () => async dispatch => {
try {
// const revoke = await API.logout()
dispatch({
type: IS_AUTHENTICATED,
payload: null
});
//should automatically display logout nav
//or redirect to anther page
} catch(e) {
//just refresh page
}
}
and these are my reducers
import {
IS_AUTHENTICATED,
AUTHENTICATION_FAILED
} from '../constants/actionTypes';
const initialState = {
user: null
}
const authReducer = (state = initialState, {type, payload}) => {
switch(type) {
case IS_AUTHENTICATED:
return {...state, user: payload, userInfo: payload}
case AUTHENTICATION_FAILED:
return {...state, user: null, authError: payload}
default:
return state
}
}
export default authReducer;
As you can see I tried to pass user.name but i keep getting cannot read property of null if I do const { user } = this.props
and i get cannot read property of undefined if i do const { user } = this.state.
I figured it out i justed needed to add
<span>
<h1 className="title">Hi {user.name}</h1>
</span>
and it worked!
I was driven crazy by my first react-redux app. My Redux State is never updated.
I tried to find every solution on the website but they are not helping. One very similar question here used promise but I am not.
Redux-dev-tools catch the actions about the login_success but the global state is never updated, please tell me what should I do to debug if you could, thank you so much.
First Index.js
import ... from ...
const compostEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const rootReducer = combineReducers({
auth: authReducer,
})
const store = createStore(rootReducer, compostEnhancer(
applyMiddleware(thunk)
));
const app = (<BrowserRouter><App /></BrowserRouter>)
ReactDOM.render(<Provider store={store}>{app}</Provider>, document.getElementById('root'));
registerServiceWorker();
authReducer.js :
import * as actionTypes from '../actions/actionTypes';
const initialState = {
token: null,
userId: null,
error: null,
loading: false
}
const authReducer = (state = initialState, action) => {
switch (action.types) {
case actionTypes.LOGIN_START:
return {
...state,
};
case actionTypes.LOGIN_SUCCESS:
return {
...state,
token: action.idToken,
userId: action.userId,
loading: false,
error:null
}
default:
return state;
}
}
export default authReducer;
authAction.js:
import * as actionTypes from './actionTypes';
import axios from 'axios';
export const loginStart= () =>{
return {
type: actionTypes.LOGIN_START
};
}
export const loginSuccess = (token,userId) =>{
return {
type: actionTypes.LOGIN_SUCCESS,
userId: userId,
idtoken: token,
}
}
export const loginFail = (error) =>{
return {
type:actionTypes.LOGIN_FAIL,
error:error
}
}
export const auth = (email,password,isSignup ) =>{
return dispatch =>{
dispatch(loginStart());
const authData = {
email: email,
password: password,
returnSecureToken:true
}
let url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=...'
if(!isSignup ){
url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=...'
}
axios.post(url, authData)
.then( response =>{
console.log(response);
dispatch(loginSuccess(response.data.idToken, response.data.localId))
})
.catch(err=>{
console.log(err);
dispatch(loginFail(err));
})
}
}
Login.js (Component):
import ... from ...;
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
isSignup: false,
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit = e => {
e.preventDefault();
// This will trigger actions
this.props.onAuth(this.state.email, this.state.password, this.state.isSignup);
console.log(this.props.token) //here I can Get Token
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
render() {
let form =
<div className={classes.ContactData} >
<h4>Sign IN</h4>
<form onSubmit={this.handleSubmit} >
<Input
elementType='input'
name="email"
required
label="Email"
placeholder="Email"
value={this.state.email}
margin="normal"
onChange={this.handleChange}
/>
<br />
<Input
elementType='input'
required
name="password"
value={this.state.password}
label="Password"
onChange={this.handleChange}
/>
<br />
<Button
color="primary"
type="submit"
>Submit</Button>
<Button color="primary" href="/"> CANCLE</Button>
</form>
</div>
if (this.props.loading) {
form = <Spinner />
}
let errorMessage = null;
if (this.props.error) {
errorMessage =(
<p>{this.props.error.message} </p>
)
}
let token = null;
if(this.props.token){
token = this.props.token.toString()
}
return (
<div>
{errorMessage}
{ form }
</div>
)
}
}
const mapStateToProps = state => {
return {
loading: state.auth.loading,
error: state.auth.error,
token:state.auth.idToken,
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (email, password, isSignup) => dispatch(actions.auth(email, password, isSignup)),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
And also, the problem leads to my Spinner and show ErrorMessage not working.
I suppose its a typo.
instead of
switch (action.types)
try this
switch (action.type)
In reducer, we get an object returned from the actions, on the argument action.