Error in returned value of mapDispatchToProps - reactjs

I'm getting the following error for my code:
Uncaught (in promise) TypeError: _this2.props.login is not a function
at Login.js:37 (for a valid user I get the message "Authorized" without any problem).
When I console log the props what I get is this**{match: {…}, location: {…}, history: {…}, staticContext: undefined}**
import React, { Component } from 'react'
import fetch from 'isomorphic-fetch';
import {connect} from 'react-redux';
import {loginUser} from '../../actions/LoginActions'
export class Login extends Component {
constructor(props) {
super(props)
this.state = {
email:"",
password:""
}
this.handleSubmit=this.handleSubmit.bind(this);
}
handleSubmit(event) {
console.log(this.state.email);
event.preventDefault();
fetch("http://127.0.0.1:3001/user/login",{
method:'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
UserEmail:this.state.email,
Password:this.state.password,
})},{withCredentials:'include'})
.then (res=>res.json())
.then (res=>{
if(res.message==='Authorized'){
console.log("authorized");
console.log(this.props);
let { email, password } = this.state;
**this.props.login(email,password);** //here I get the error
this.setState({
email : "",
password : ""
});
localStorage.setItem('sessionType', res.result.sessionType);
localStorage.setItem("UserId" , res.result.UserId);
}
else{
console.log("error");
}
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<formgroup>
<input
type="email"
value={this.state.email}
onChange={(event)=>{this.setState({ email: event.target.value })}}
placeholder="Email"
id="email"
required
/>
</formgroup>
<formgroup>
<input
type="password"
value={this.state.password}
type="password"
onChange={(event)=>{this.setState({ password: event.target.value })}}
placeholder="Password "
id="password"
required
/>
</formgroup>
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => {
return({
login: (email,password) => {dispatch(loginUser(email,password))}
})
}
const mapStateToProps = (state) =>{
return{}
}
export default connect (mapStateToProps,mapDispatchToProps) (Login)
LoginUser Action file :
import * as actionType from './ActionType';
import fetch from 'isomorphic-fetch';
export const loginBegin =(isloginPending) =>({
type :actionType.LOGIN_BEGINS,
payload:isloginPending
});
export const login =(isloginSuccess) =>({
type :actionType.LOGIN_COMPLETE,
payload:isloginSuccess
});
export const loginError =(isloginError) =>({
type :actionType.LOGIN_ERROR,
payload:isloginError
});
export function loginUser(email, password) {
return dispatch => {
dispatch(loginBegin(true));
dispatch(login(false));
dispatch(loginError(null));
callLoginApi(email, password, error => {
dispatch(loginBegin(false));
if (!error) {
dispatch(login(true));
} else {
dispatch(loginError(error));
}
});
}
}

in mapDispatchToProps you return one object, have you tried removing the parentheses in the function?
const mapDispatchToProps = (dispatch) => {
return {
login: (email,password) => {dispatch(loginUser(email,password))}
}
}

mapDispatchToProps is supposed to be just an object.
const mapDispatchToProps = {
login: loginUser
}
loginUser is the action that you're importing to mapDispatchToProps and you're assinging that as this.props.login.

Related

error messages under the relevant input fields automatically from Django Rest API by react hooks

i want to display every error messages from Django Rest Api automatically in React frontend. i wanted to test my concept with the signup authentication function and after fixing it i would like to use the concept in every components in fetching data from or into django API.
here is my App.js to register a user just for test:
import React, { useState } from "react";
export default function Signup() {
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password1, setPassword1] = useState("");
const [password2, setPassword2] = useState("");
const [user, setUser] = useState("");
function handleEmail(evt) {
setEmail(evt.target.value);
}
function handleUsername(evt) {
setUsername(evt.target.value);
}
function handlePassword1(evt) {
setPassword1(evt.target.value);
}
function handlePassword2(evt) {
setPassword2(evt.target.value);
}
function handle_signup(evt) {
evt.preventDefault();
fetch("http://127.0.0.1:8000/api/v1/rest-auth/registration/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username, email, password1, password2 }),
})
.then((res) => res.json())
.then((json) => {
localStorage.setItem("token", json.key);
console.log(json);
setUser(json.username);
})
.catch((err) => {
if(err.res){
console.log(err.res.username)
console.log(err.res.email);
console.log(err.res.password1);
console.log(err.res.password2);
}else if(err.res){
console.log(err.res)
}else{
console.log('Error',err.message)
}
console.log(err.config);
});
}
return (
<form onSubmit={(evt) => handle_signup(evt, setUser())}>
<label htmlFor="register-username">Username:</label>
<input
type="text"
value={username}
onChange={handleUsername}
name="register-username"
id="register-username"
/>
<label htmlFor="register-email">Email:</label>
<input
type="text"
value={email}
onChange={handleEmail}
name="register-username"
id="register-username"
/>
<label htmlFor="register-password1">Password1:</label>
<input
type="password1"
value={password1}
onChange={handlePassword1}
name="register-password1"
id="register-password1"
/>
<label htmlFor="register-password2">password2:</label>
<input
type="password2"
value={password2}
onChange={handlePassword2}
name="register-password2"
id="register-password2"
/>
<input type="submit" value="Register" />
</form>
);
}
in UseEffect i have tried to show every error message under relevant input boxes which are username, email, password1, password2, i tried to do it by React-hook-form but it will be like inserting error messages from frontend. but i want to show actual error messages from backend. in development tools, when i try upper codes by putting wrong infos in input boxes, it would only show POST: 400 (bad request)
how can i show such error messages under every input boxes like Username exist or email address is invalid, or password must be at least 8 which are typical in Django Rest API's typical error messages ?
FYI: this code can register any user if the input boxes are correctly filled up.
The code below is from my article React Token-Based Authentication to Django REST API Backend. It is using react-bootstrap. It is a simple example with username and password, but you can easily extend it.
If there is a known error (axios docs about handling errors) I check if it has a message for username or password. If yes, then I set an error message for FormControl.Feedback. If you don't want to use react-bootstrap you can just make a small red text inside div and make it visible only if the error message is set (not empty).
// frontend/src/components/SignupReducer.js
// import needed actions
import {
CREATE_USER_ERROR,
CREATE_USER_SUBMITTED,
CREATE_USER_SUCCESS
} from "./SignupTypes";
// define the initial state of the signup store
const initialState = {
usernameError: "",
passwordError: "",
isSubimtted: false
};
// define how action will change the state of the store
export const signupReducer = (state = initialState, action) => {
switch (action.type) {
case CREATE_USER_SUBMITTED:
return {
usernameError: "",
passwordError: "",
isSubimtted: true
};
case CREATE_USER_ERROR:
const errorState = {
usernameError: "",
passwordError: "",
isSubimtted: false
};
if (action.errorData.hasOwnProperty("username")) {
errorState.usernameError = action.errorData["username"];
}
if (action.errorData.hasOwnProperty("password")) {
errorState.passwordError = action.errorData["password"];
}
return errorState;
case CREATE_USER_SUCCESS:
return {
usernameError: "",
passwordError: "",
isSubimtted: false
};
default:
return state;
}
}
// frontend/src/components/signup/SignupActions.js
import axios from "axios";
import { toast } from "react-toastify";
import { isEmpty } from "../../utils/Utils";
import {
CREATE_USER_ERROR,
CREATE_USER_SUBMITTED,
CREATE_USER_SUCCESS
} from "./SignupTypes";
export const signupNewUser = userData => dispatch => {
dispatch({ type: CREATE_USER_SUBMITTED }); // set submitted state
axios
.post("/api/v1/users/", userData)
.then(response => {
toast.success(
"Account for " +
userData.username +
" created successfully. Please login."
);
dispatch({ type: CREATE_USER_SUCCESS });
})
.catch(error => {
if (error.resposne) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
toast.error(JSON.stringify(error.response.data));
dispatch({
type: CREATE_USER_ERROR,
errorData: error.response.data
});
} else if (error.message) {
// the error message is available,
// let's display it on error toast
toast.error(JSON.stringify(error.message));
} else {
// strange error, just show it
toast.error(JSON.stringify(error));
}
});
};
// frontend/src/components/signup/Signup.js file
import React, { Component } from "react";
import { withRouter } from "react-router-dom"; // new import
import { connect } from "react-redux"; // new import
import PropTypes from "prop-types"; // new import
import { Link } from "react-router-dom";
import {
Container,
Button,
Row,
Col,
Form,
FormControl
} from "react-bootstrap";
import { signupNewUser } from "./SignupActions"; // new import
class Signup extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
};
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
// update function to call the action
onSignupClick = () => {
const userData = {
username: this.state.username,
password: this.state.password
};
this.props.signupNewUser(userData); // <-- signup new user request
};
render() {
return (
<Container>
<Row>
<Col md="4">
<h1>Sign up</h1>
<Form>
<Form.Group controlId="usernameId">
<Form.Label>User name</Form.Label>
<Form.Control
isInvalid={this.props.createUser.usernameError}
type="text"
name="username"
placeholder="Enter user name"
value={this.state.username}
onChange={this.onChange}
/>
<FormControl.Feedback type="invalid">
{this.props.createUser.usernameError}
</FormControl.Feedback>
</Form.Group>
<Form.Group controlId="passwordId">
<Form.Label>Your password</Form.Label>
<Form.Control
isInvalid={this.props.createUser.passwordError}
type="password"
name="password"
placeholder="Enter password"
value={this.password}
onChange={this.onChange}
/>
<Form.Control.Feedback type="invalid">
{this.props.createUser.passwordError}
</Form.Control.Feedback>
</Form.Group>
</Form>
<Button color="primary" onClick={this.onSignupClick}>
Sign up
</Button>
<p className="mt-2">
Already have account? <Link to="/login">Login</Link>
</p>
</Col>
</Row>
</Container>
);
}
}
// connect action and reducer
// replace
// export default Signup;
// with code below:
Signup.propTypes = {
signupNewUser: PropTypes.func.isRequired,
createUser: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
createUser: state.createUser
});
export default connect(mapStateToProps, {
signupNewUser
})(withRouter(Signup));

In React-Redux app, trying to pre-fill the default value in Edit Component with current api calls value

In my reactredux app, There is a peculiar situaton where I am currently trying to pre-fill my input field in Edit component but the thing is ,Its getting filled but not with current api calls but with last api calls that happens inside componentDidMount().I tried to clear the object too but all in vain. Kindly suggest
ProfileEdit.js component
import React, { Component } from 'react';
import '../App.css';
import {connect} from 'react-redux';
import {profileFetchDetail} from '../actions/profile';
import { withRouter } from 'react-router-dom';
class ProfileEdit extends Component {
constructor(props){
super(props);
this.state = {
firstName: '',
lastName: '',
emailId: '',
}
}
componentDidMount(){
const id = this.props.match.params.id;
this.props.profileFetchDetail(id);
this.setState({
firstName: this.props.profile.firstName,
lastName: this.props.profile.lastName,
emailId: this.props.profile.emailId
})
}
render() {
const {firstName,lastName,emailId} = this.state;
console.log(this.props.profile);
return (
<form name="profileCreate" className="profile-form">
<div className="form-control">
<label htmlFor="firstName">First Name</label><br/>
<input type="text" id="firstName" defaultValue={firstName}
name="firstName" placeholder="First Name"
/>
</div>
<div className="form-control">
<label htmlFor="LastName">Last Name</label><br/>
<input type="text" id="LastName" defaultValue={lastName}
name="lastName" placeholder="Last Name"
/>
</div>
<div className="form-control">
<label htmlFor="email">Email</label><br/>
<input type="email" id="email" defaultValue={emailId}
/>
</div>
<div className="form-action">
<input type="submit" value="Click here" />
</div>
</form>
)
}
}
const mapStateToProps = state => ({
profile: state.profile.profile
})
export default connect(mapStateToProps, {profileFetchDetail})(withRouter(ProfileEdit));
Action creators, here profileFetchDetail() is of our interest
import api from '../api';
// profile create
export const profileAdd = (formData, history) => async dispatch => {
console.log(formData);
const config = {
headers : { 'Content-Type': 'application/json' }
}
try {
await api.post('/api/profile/create', formData, config);
dispatch({ type: 'CREATE_PROFILE', payload: formData });
history.push('/list');
} catch (error) {
console.log(error);
}
}
// profile get all list
export const profileFetch = () => async dispatch => {
try {
const res = await api.get('/api/profile/list');
dispatch({ type: 'GET_PROFILE', payload: res.data });
} catch (error) {
console.log(error);
}
}
// profile get single list item corresponding to id
export const profileFetchDetail = (id) => async dispatch => {
dispatch({ type: 'CLEAR_PROFILE' });
try {
const res = await api.get(`/api/profile/${id}`);
dispatch({ type: 'GET_PROFILE_SINGLE', payload: res.data });
} catch (error) {
console.log(error);
}
}
// profile delete
export const profileDelete = (id) => async dispatch => {
dispatch({ type: 'CLEAR_PROFILE' });
try {
const res = await api.delete(`/api/profile/${id}/delete`);
dispatch({ type: 'DELETE_PROFILE', payload: res.data });
dispatch(profileFetch());
} catch (error) {
console.log(error);
}
}
ProfileReducers
const initialState = {
profiles:[],
profile:{}
};
export default (state = initialState, action) => {
switch (action.type) {
case 'CREATE_PROFILE':
return {...state, profiles: [...state.profiles, action.payload]};
case 'GET_PROFILE':
return {...state, profiles: action.payload};
case 'GET_PROFILE_SINGLE':
return {...state, profile: action.payload};
case 'CLEAR_PROFILE':
return {...state, profile: {}};
case 'DELETE_PROFILE':
return {...state, profiles: state.profiles.filter( item => item._id !== action.payload) };
default:
return state;
}
};
First time it loads perfectly on clicking edit button then the issue happens on clicking any other edit button.Pasting the example of 2 api calls inside componentDidMount().
In the attached image, the last api request in sequence displayed is the currently made request.Api made detail
Note: Till now I am not trying to edit it just prefilling data,where issue happening.

Can't perform a React state update on an unmounted component with redux

Two components are rendered with conditional rendering with a redux state but after changing redux state from one component warning appears that can't perform state update on unmounted component. In LoginWrapper.js Login and Redirect are two components with conditional rendering using isLoggedIn state of redux.
LoginWrapper.js
import React from 'react';
import Login from 'containers/Login';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { PropTypes } from 'prop-types';
const LoginWrapper = ({ isLoggedIn }) => {
return (
<div>
{
!isLoggedIn
?
<Login />
:
<Redirect to="/profile" />
}
</div>
)
}
LoginWrapper.defaultProps = {
isLoggedIn: false
}
LoginWrapper.propTypes = {
isLoggedIn: PropTypes.bool
}
const mapStateToProps = (state) => {
return {
isLoggedIn: state.auth.isLoggedIn
}
}
export default connect(mapStateToProps)(LoginWrapper);
Login.js
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter, Link } from 'react-router-dom';
import { withFormik, Form, Field } from 'formik';
import { connect } from 'react-redux';
import { logInUser } from 'actions/auth';
import { logInUrl } from "apis";
import ModalLayout from "shared/ModalLayout";
import * as Yup from 'yup';
const loginPost = (history, values, setSubmitting, setErrors, resetForm, logIn) => {
const { username, password } = values;
window.fetch(logInUrl, {
method: 'POST',
credentials: "same-origin",
headers: {
'Content-Type': "application/json"
},
body: JSON.stringify({
"username": username,
"password": password
})
})
.then((results) => {
return results.json();
})
.then((data) => {
if(data.errors) {
setErrors({ 'username': data.errors[0].msg });
} else {
logIn(data.user, history);
resetForm();
}
setSubmitting(false);
})
.catch((err) => {
console.log(err);
})
}
const LogInForm = ({
touched,
errors,
isSubmitting,
}) => (
<ModalLayout>
<Form className="login-form">
{touched.username && errors.username && <p className="login-error">{errors.username}</p>}
<div className="login-username">
<Field type="input" placeholder="Username" name="username" />
</div>
{touched.password && errors.password && <p className="login-error">{errors.password}</p>}
<div className="login-password">
<Field type="password" placeholder="Password" name="password" />
</div>
<div className="login-button">
<button className="modal-button login-button" type="submit" disabled={isSubmitting}>
Log in
</button>
</div>
<div className="login-redirect">
<Link to="/signup">Don&apos;t have an account.Create one</Link>
</div>
</Form>
</ModalLayout>
);
LogInForm.propTypes = {
isSubmitting: PropTypes.bool.isRequired,
errors: PropTypes.object.isRequired,
touched: PropTypes.object.isRequired,
}
const FormikApp = withFormik({
mapPropsToValues() {
return {
username: '',
password: '',
}
},
handleSubmit(values, { resetForm, setErrors, setSubmitting, props }) {
const { logIn, history } = props;
loginPost(history, values, setSubmitting, setErrors, resetForm, logIn);
},
validationSchema: Yup.object().shape({
username: Yup.string().required('Username is required'),
password: Yup.string().required('Password is required'),
})
})(LogInForm);
export default withRouter(connect(null, { logIn: logInUser })(FormikApp));
actions
import {
LOG_IN,
LOG_OUT,
} from 'actions/types';
import { logInUrl } from 'apis';
export const logInUser = (user) => {
return (dispatch) => {
dispatch({
type: LOG_IN,
payload: user
})
}
}
export const logOutUser = () => {
return {
type: LOG_OUT
}
}
reducers
import { LOG_IN, LOG_OUT } from 'actions/types';
const INITIAL_STATE = {
isloggedIn: null,
user: null,
uid: null
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case LOG_IN:
return { ...state, isLoggedIn: true, user: action.payload, uid: action.payload.id }
case LOG_OUT:
return { ...state, isLoggedIn: false, user: null, uid: null };
default:
return state;
}
};

Why won't Axios give me a response with Redux actions?

I am trying to make a simple signup form. I have a redux form that I'm trying to send some user data to my express backend with. I am trying to do this through redux actions via this redux action:
Ultimately, I'd like to receive a response, and redirect or give errors if necessary. The backend seems to receive the data and can validate, but axios receiving the response to let redux know to update the state. Any ideas?
Edit: I also tried putting the axios request inside of the signupForm itself, and still had issues(wasn't able to get a response).
Edit: Here is the repo if you'd like to see all the files: https://github.com/capozzic1/react-blog
redux signup action:
import axios from 'axios';
import { SubmissionError } from 'redux-form';
/* eslint-disable */
export const signUp = userData => dispatch => axios.post('/api/users', userData)
.then((response) => {
dispatch({ type: 'SIGNUP_REDIRECT_YES ', payload: true})
// this.props.history.go('/');
console.log(response);
})
.catch((error) => {
console.log(error.response);
dispatch({ type: 'SIGNUP_REDIRECT_NO ', payload: false})
throw new SubmissionError({ _error: 'Login failed!' });
});
Also with this signup form component (redux-form):
class SignUpForm extends React.Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(userData) {
this.props.signup(userData);
}
render() {
const { error, handleSubmit, pristine, reset, submitting } = this.props;
return (
<form >
{error && (<strong>{error}</strong>)}
<Field name="username" type="text" component={renderField} label="Username" />
<Field name="email" type="email" component={renderField} label="Email" />
<Field name="password" type="text" component={renderField} label="Password" />
<Field name="passwordConfirm" type="text" component={renderField} label="Enter password to confirm" />
<div>
<button type="button" disabled={submitting} onClick={handleSubmit(this.onSubmit)}>Sign Up</button>
<button type="button" onClick={reset}>Clear Values</button>
</div>
</form>
);
}
}
export default reduxForm({
form: 'signUpForm',
})(SignUpForm);
This form is being fed by a container component(thought this was a standard pattern? Let me know if it's not).
Sign up page container:
const mapDispatchToProps = dispatch => ({
signup: (user) => {
dispatch(signUp(user));
},
});
const SignUp = props => (
<Layout>
<SignUpForm signup={props.signup} />;
</Layout>
);
export default connect(null, mapDispatchToProps)(SignUp);
Here is the sign up reducer:
export default function reducer(state = {
signupRedirect: false,
}, action) {
switch (action.type) {
case 'SIGNUP_REDIRECT_YES': {
return {
...state, signupRedirect: action.payload,
};
}
case 'SIGNUP_REDIRECT_NO' : {
return {
...state, signupRedirect: action.payload,
};
}
}
return state;
}
Here is my store:
import { applyMiddleware, createStore, compose } from 'redux';
import { createLogger } from 'redux-logger';
import thunk from 'redux-thunk';
import promise from 'redux-promise-middleware';
import reducer from './reducers';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(
applyMiddleware(promise(), thunk, createLogger()),
));
export default store;
It doesn't work because your anonymous function returned by signUp function returns a promise. Use brackets to avoid default behaviour.
export const signUp = userData => dispatch => {
axios.post('/api/users', userData)
.then((response) => {
dispatch({ type: 'SIGNUP_REDIRECT_YES ', payload: true})
// this.props.history.go('/');
console.log(response);
})
.catch((error) => {
console.log(error.response);
dispatch({ type: 'SIGNUP_REDIRECT_NO ', payload: false})
throw new SubmissionError({ _error: 'Login failed!' });
});
}

How to pass my error message from server called by axios to my component

I'm really new to React. I have an axios request in my actions I want my error message to pass on the component I have this code :
import axios from 'axios';
import setAuthorizationToken from '../utils/setAuthorizationToken';
import jwtDecode from 'jwt-decode';
import { SET_CURRENT_USER, BASE_URL } from './types';
const instance = axios.create({
baseURL: BASE_URL
});
export function setCurrentUser(user) {
return {
type: SET_CURRENT_USER,
user
};
}
export function logout() {
return dispatch => {
localStorage.removeItem('accessToken');
localStorage.removeItem('refreshToken');
setAuthorizationToken(false);
dispatch(setCurrentUser({}));
}
}
export function login(data) {
return dispatch => {
return instance.post('/authenticate', data).then(function(response) {
const token = response.data.accessToken;
const refreshToken = response.data.refreshToken;
localStorage.setItem('accessToken', token);
localStorage.setItem('refreshToken', refreshToken);
setAuthorizationToken(token);
dispatch(setCurrentUser(jwtDecode(token)));
})
.catch(function(error){
console.log('error: ', error.response.data);
});
}
}
Here is my Component:
import React from 'react';
import TextFieldGroup from '../common/TextFieldGroup';
import validateInput from '../../server/validations/login';
import { connect } from 'react-redux';
import { login } from '../../actions/authActions';
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
errors: {},
isLoading: false
};
this.onSubmit = this.onSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
isValid() {
const { errors, isValid } = validateInput(this.state);
if (!isValid) {
this.setState({ errors });
}
return isValid;
}
onSubmit(e) {
e.preventDefault();
if (this.isValid()) {
this.setState({ errors: {}, isLoading: true });
this.props.login(this.state).then(
(res) => this.context.router.push('/'),
(error) => this.setState({ errors: error.response.data , isLoading: false }),
);
}
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
const { errors, username, password, isLoading } = this.state;
return (
<form onSubmit={this.onSubmit}>
<h1>Login</h1>
{ errors.message && <div className="alert alert-danger">{errors.message}</div> }
<TextFieldGroup
field="username"
label="Username"
value={username}
error={errors.username}
onChange={this.onChange}
/>
<TextFieldGroup
field="password"
label="Password"
value={password}
error={errors.password}
onChange={this.onChange}
type="password"
/>
<div className="form-group"><button className="btn btn-primary btn-lg" disabled={isLoading}>Login</button></div>
</form>
);
}
}
LoginForm.propTypes = {
login: React.PropTypes.func.isRequired
}
LoginForm.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default connect(null, { login })(LoginForm);
Here is the console.log
error: Object {code: "UNAUTHORIZED", message: "Invalid username or password."}
Currently I don't know to pass my error message to component. I'm really new to React and Redux
First you have to add the initial state on reducer. For example
authReducer.js
const initialState = {
... // another state
errors: {}
}
function yourReducer(state = initialState, action) {
case 'SHOW_ERROR':
return {
...state,
errors: action.message
}
default:
return state
}
On login action dispatch the 'SHOW_ERROR'
authActions.js
export function login(data) {
return dispatch => {
return instance.post('/authenticate', data).then(function(response) {
...
// success
})
.catch(function(error){
// fail
dispatch({ type: 'SHOW_ERROR', message: error.response.data })
});
}
}
Then you need to map redux state to be a props on your component
LoginComponent.js
function mapStateToProps(state) {
return {
you: may.return.another.state.here,
errors: state.yourReducerName.errors
}
}
export default connect(mapStateToProps, { login })(LoginForm);
Finally, you can call errors as a props on your Component
class LoginForm extends React.Component {
...
render() {
const { errors, username, password, isLoading } = this.state;
const { errors } = this.props // errors from redux state
return (
<form onSubmit={this.onSubmit}>
<p>{errors.message}</p>
<h1>Login</h1>
...
<div className="form-group"><button className="btn btn-primary btn-lg" disabled={isLoading}>Login</button></div>
</form>
);
}
}
Don't forget to validate the prop types. Good luck!

Resources