I'm a PHP/Laravel mid-level developer. I'm totally a noob when it comes to react.js. Now I know that react uses API's and stuff to show data when it comes to laravel backend. I am used to traditional HTML, CSS, JS, Bootstrap, Ajax and whatsoever. I have a simple task to login a user from react through laravel backend. I'v created the APIs for that task and they're working totally fine and somehow I got lucky and attached those APIs ALL BY MYSELF (with a little research, of course). Now whenever I try to signin, I receive the usual data through an axios request to backend and have it in a variable signInUser. Now when I try to pass that data to other action function it's going undefined somehow. Here's my code so that you can understand what I'm trying to achieve:
Components\SignIn.js
constructor() {
super();
this.state = {
email: '',
password: ''
}
}
componentDidUpdate() {
if (this.props.showMessage) {
setTimeout(() => {
this.props.hideMessage();
}, 100);
}
if (this.props.authUser !== null) {
this.props.history.push('/');
}
}
render() {
const {email, password} = this.state;
const {showMessage, loader, alertMessage} = this.props;
return (
// other components and stuff...
<Button onClick={() => { this.props.showAuthLoader(); this.props.userSignIn({email, password});}} variant="contained" color="primary">
<IntlMessages id="appModule.signIn"/>
</Button>
);
}
const mapStateToProps = ({auth}) => {
const {loader, alertMessage, showMessage, authUser} = auth;
return {loader, alertMessage, showMessage, authUser}
};
export default connect(mapStateToProps, {
userSignIn,
hideMessage,
showAuthLoader
})(SignIn);
Sagas\Auth.js
const signInUserWithEmailPasswordRequest = async (email, password) =>
await axios.post('auth/login', {email: email, password: password})
.then(authUser => authUser)
.catch(err => err);
function* signInUserWithEmailPassword({payload}) {
const {email, password} = payload;
try {
const signInUser = yield call(signInUserWithEmailPasswordRequest, email, password);
if (signInUser.message) {
yield put(showAuthMessage(signInUser.message));
} else {
localStorage.setItem('user_id', signInUser.data.user.u_id);
yield put(userSignInSuccess(signInUser.data.user.u_id));
}
} catch (error) {
yield put(showAuthMessage(error));
}
}
export function* signInUser() {
yield takeEvery(SIGNIN_USER, signInUserWithEmailPassword);
}
export default function* rootSaga() {
yield all([fork(signInUser),
// couple of other functions...
);
}
actions\Auth.js
export const userSignIn = (user) => {
return {
type: SIGNIN_USER,
payload: user
};
};
export const userSignInSuccess = (authUser) => {
console.log(authUser); // It's printing undefined, I don't know why?!
return {
type: SIGNIN_USER_SUCCESS,
payload: authUser
}
};
reducers\Auth.js
const INIT_STATE = {
loader: false,
alertMessage: '',
showMessage: false,
initURL: '',
authUser: localStorage.getItem('user_id'),
};
export default (state = INIT_STATE, action) => {
switch (action.type) {
case SIGNIN_USER_SUCCESS: {
return {
...state,
loader: false,
authUser: action.payload
}
}
case INIT_URL: {
return {
...state,
initURL: action.payload
}
}
default:
return state;
}
}
P.s: It's a purchased react.js template (not my code).
Related
i am trying to send the error messages that sent from my server ( express ) to axios and the error message displays in toastify component but the error message doesn't show up here is the login axios function with the toastify how can i display toastify message inside my page from redux ?
here is my code :
// redux controller
const login = async (username, password) => {
await axios.post("/login",{username,password,},
{ withCredentials: true });};
// reducer page
export function generateError(prop) {
return function (dispatch) {
dispatch({
type: "USER_FAIL"
});
toast.error(prop);
};
}
export function generateSuccess(prop) {
return function (dispatch) {
dispatch({
type: "USER_SUCCESS"
});
toast.success(prop);
};
}
export const login = createAsyncThunk(
"/login",
async ({ username, password }) => {
try {
const data = await authService.login(username, password);
if (data) {
if (data.errors) {
const { username, password } = data.errors;
if (username) generateError(username)
else if (password) generateError(password);
} else {
generateSuccess(data.success);
}
}
return { user: data };
} catch (error) {
console.log(error);
}
}
);
// login page
const handleSubmit = (e) => {
e.preventDefault();
dispatch(login({ username, password }));
}
i am using react-tostify and #redux-toolkit but the message doesn't display inside my page
i fixed it and here is my code :
// auth.js ( redux page )
export const login = createAsyncThunk(
"/login",
async ({ username, password }) => {
try {
const {data} = await axios.post(
"/login",
{
username,
password,
},
{ withCredentials: true }
);
return { user: data };
} catch (error) {
console.log(error);
}
});
const initialState = user
? { isLoggedIn: true, user }
: { isLoggedIn: false, user: null };
const authSlice = createSlice({
name: "auth",
initialState,
extraReducers: {
[login.fulfilled]: (state, action) => {
state.isLoggedIn = true;
state.user = action.payload.user;
},
[login.rejected]: (state, action) => {
state.isLoggedIn = false;
state.user = null;
},
[logout.fulfilled]: (state, action) => {
state.isLoggedIn = false;
state.user = null;
},
}})
const { reducer } = authSlice; export default reducer;
Login Page :
const { isLoggedIn } = useSelector((state) => state.auth);
const dispatch = useDispatch();
const handleSubmit = (e) => {
e.preventDefault();
dispatch(login({ username, password })).then(data => {
console.log(data)
if (data.payload.user) {
if (data.payload.user.errors) {
const { username, password } = data.payload.user.errors;
if (username) generateError(username)
else if (password) generateError(password);
} else {
generateSuccess(data.success);
navigate("/dashboard");
}
}
})
}
i realized when i back the data it has an object name payload i used it to get the error messages from express and then i put the message in toastify function gettingError and here it is
const generateError = error => {
toast.error(error, {
position: "bottom-right",
})
}
Hai I'm also looking for the same problem while searching I found a solution at with this : react-toastify-with-redux
my Code : authAction.js
import 'react-toastify/dist/ReactToastify.min.css';
import { toast} from 'react-toastify';
export const registerUser = (userData) => dispatch =>{
axios.post('user/register',userData)
.then(res=>toast.success('Your Account Created Successfully 👍'))
.then(res=> window.location = '/authentication/sign-in')
.catch(err=>dispatch(
{
type: GET_ERRORS,
payload: err.response.data
}
),toast.error("Error 😣"))
// .catch((err)=> {return })
};
On your signUp page just add
<ToastContainer />
That's all ...
This answer is probably late. But I came across this problem and decided to do it my way. I know there is toast. promise to handle promises and I don't want to call dispatch.then every time. So I can up with passing dispatch to my action wrapper. Here is my code.
// utils.ts
type ArgumentTypes<F extends CallableFunction> = F extends (
...args: infer A
) => any
? A[0]
: never;
export const withToast = <T = AnyAction | typeof createAsyncThunk>(
action: T,
{ pending, error, success }: ToastPromiseParams<T>
) => {
return (
dispatch: ReturnType<typeof useAppDispatch>,
actionParams?: ArgumentTypes<T & CallableFunction> | void
) => {
const promise = dispatch(
(action as CallableFunction)(actionParams as any)
).unwrap();
toast.promise(promise, {
pending,
error,
success,
});
};
};
// actions.ts
export const login = createAsyncThunk(
"user/login",
async (payload: {
email: string;
password: string;
}): Promise<Partial<LoginAPIResponse>> => {
const { data } = await axios.post(`${API}/${LOGIN_EP}/`, payload);
return data;
}
);
export const loginWithToast = withToast(login, {
pending: "Logging in...",
error: {
render: (error: any) => {
return error?.password || error?.email
? "Invalid email or password"
: "Something went wrong";
},
},
success: "Logged in successfully",
});
// usage in component
const dispatch = useAppDispatch();
loginWithToast(dispatch, {
email: values.email.value,
password: values.password.value,
});
First createAsyncThunk:
import { coreAxios } from "utilities/axios"; // Own customized axios
import { createAsyncThunk } from "#reduxjs/toolkit";
const BASE_URL = process.env.REACT_APP_MAIN_URL
export const GetProducts = createAsyncThunk(
"inventory/GetProducts",
async () => {
const {data} = await coreAxios.get(`${BASE_URL}/api/product/list/`);
return data
}
);
Second createSlice:
import { createSlice } from "#reduxjs/toolkit";
import { GetProducts } from "services/inventory/product.service";
import { toast } from 'react-toastify';
export const productSlice = createSlice({
name: "products",
initialState: {
productsList: [],
productsLoading: false,
productsError: null,
},
extraReducers:
(builder) => {
builder.addCase(GetProducts.pending, (state) => {
toast.loading('Promise is pending...')
state.productsLoading = true
});
builder.addCase(GetProducts.fulfilled, (state, action) => {
toast.dismiss();
toast.success('Promise resolved 👌');
state.productsList = action.payload
state.productsLoading = false
state.productsError = null
});
builder.addCase(GetProducts.rejected, (state, action) => {
toast.dismiss();
toast.error('Promise rejected 🤯 😣')
state.productsLoading = false
state.productsError = action.error?.message
});
},
});
export default productSlice.reducer;
Third page:
import { ToastContainer } from 'react-toastify';
import { useSelector, useDispatch } from "react-redux";
import { GetProducts } from 'services/inventory/product.service';
const Product = () => {
const { productsList, productsLoading, productsError } = useSelector((state) => state.products);
const dispatch = useDispatch();
useEffect(() => {
dispatch(GetProducts());
}, []);
return (
<div className="grid crud-demo">
<h1>Hello Alim</h1>
<ToastContainer />
</div>
);
}
isAuthenticated is undefined when i run this code. how can is use isAuthenticated with mapStateProps. if i am use Token `(Token '5302f4340a76cd80a855286c6d9e0e48d2f519cb'} like this then it's working fine but i want Authorized it with props.isAuthenticated anybody know how can i solve this issue?
authAction.js
import axios from 'axios';
import * as actionTypes from './actionTypes';
export const authStart = () => {
return {
type: actionTypes.AUTH_START
}
}
export const authSuccess = token => {
return {
type: actionTypes.AUTH_SUCCESS,
token: token
}
}
export const authFail = error => {
return {
type: actionTypes.AUTH_FAIL,
error: error
}
}
export const logout = () => {
localStorage.removeItem('token');
return {
type: actionTypes.AUTH_LOGOUT
};
}
export const authLogin = (userData) => {
return dispatch => {
dispatch(authStart());
axios.post('http://localhost:8000/rest-auth/login/', userData)
.then(res => {
const token = res.data.key;
localStorage.setItem('token', token);
dispatch(authSuccess(token));
})
.catch(err => {
dispatch(authFail(err))
})
}
}
authReducer.js
import * as actionTypes from '../actions/actionTypes';
import { updateObject } from '../utility';
const initialState = {
isAuthenticated: null,
token: null,
error: null,
loading: false
}
const authStart = (state, action) => {
return updateObject(state, {
isAuthenticated: false,
error: null,
loading: true
});
}
const authSuccess = (state, action) => {
return updateObject(state, {
isAuthenticated: true,
token: action.token,
error: null,
loading: false
});
}
const authFail = (state, action) => {
return updateObject(state, {
error: action.error,
loading: false
});
}
const authLogout = (state, action) => {
return updateObject(state, {
token: null
});
}
export default function (state = initialState, action) {
switch (action.type) {
case actionTypes.AUTH_START: return authStart(state, action);
case actionTypes.AUTH_SUCCESS: return authSuccess(state, action);
case actionTypes.AUTH_FAIL: return authFail(state, action);
case actionTypes.AUTH_LOGOUT: return authLogout(state, action);
default:
return state;
}
}
index.js
import { combineReducers } from 'redux';
import auth from './authReducer'
export default combineReducers({
auth: auth
});
articleList.js
const NewsList = (props) => {
// ...
const fetchItems = async () => {
try {
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Token ${props.isAuthenticated}`
}
}
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/`, config);
setItems(res.data)
setLoading(false);
}
catch (err) {
console.log(`😱 Axios request failed: ${err}`);
}
}
fetchItems()
})
}, [items]);
// ...
}
const mapStateToProps = (state) => {
return {
isAuthenticated: state.auth.token
}
}
export default connect(mapStateToProps)(NewsList)
You need to debug your code. Start by connecting the dots: The output tells you that props.isAuthenticated is undefined. You pass this in from state.auth.token in mapStateToProps():
const mapStateToProps = (state) => {
return {
isAuthenticated: state.auth.token
}
}
So state.auth.token must be undefined also. That's as far as I can get from what you have shown me. You will need to debug further to figure out why. You can use the React Dev Tools to inspect props of your components. You can use Redux Dev Tools to inspect and manipulate the redux state. Check what the value of auth.token is in state. Look where it is supposed to be set and find out why it isn't getting set to a valid value.
Be sure to check this article for tips on how to debug your code.
I am using redux to maintain my state in my react app, in my functional component i am dispatching some action in following way,
const handleClickOpen = () => {
console.log('in handle');
let data = {
reports_interval : currentSetting
};
dispatch(updateEmailSettingsAction({data: data, id: settings.id}))
};
in actions i have updateEmailSettingsAction and updateEmailSettingsActionSuccess showEmailSuccessAction which looks like following.
export const updateEmailSettingsAction = (settings) => {
console.log('in actrions');
return {
type: UPDATE_EMAIL_SETTINGS,
payload: settings
};
};
export const updateEmailSettingsActionSuccess = (settings) => {
console.log('success dispatched');
return {
type: UPDATE_EMAIL_SETTINGS_SUCCESS,
payload: settings
};
};
export const showEmailSuccessAction = (message) => {
return {
type: SHOW_EMAIL_SETTINGS_SUCCESS,
payload: message
}
};
Following are my sagas
const updateEmailSettings_request = async (data, id) =>
await updateEmailSettingsService(data, id)
.then(settings => settings)
.catch(error => error);
function* updateEmailSettingsFunction(payload) {
console.log('in func');
const {data, id} = payload.payload;
try {
const req = yield call(updateEmailSettings_request, data, id);
if (req.status === 200) {
console.log('in 200');
yield put(updateEmailSettingsActionSuccess(req.data));
yield put(showEmailSuccessAction('Success'));
}
else {
if (!req.data) {
yield put(showEmailSettingsAlert(req.message))
}else {
for (let key in req.data) {
yield put(showEmailSettingsAlert(req.data[key]));
}
}
}
} catch (error) {
yield put(showEmailSettingsAlert(error));
}
}
export function* updateEmailSettings() {
console.log('in final');
yield takeLatest(UPDATE_EMAIL_SETTINGS, updateEmailSettingsFunction)
}
and in following are my reducers.
const INIT_STATE = {
alertMessage: '',
settings: null,
successMessage: '',
showEmailSuccess: false,
};
export default (state = INIT_STATE, action) => {
switch (action.type) {
case UPDATE_EMAIL_SETTINGS_SUCCESS: {
return {
...state,
loader: false,
settings: action.payload,
}
}
case SHOW_EMAIL_SETTINGS_SUCCESS: {
console.log('in here reducer');
return {
...state,
loader: false,
showEmailSuccess: true,
successMessage: action.payload
}
}
}
i am accessing this showEmailSuccess in my component usinf useSelector in and showing success message in following way
{(showEmailSuccess && NotificationManager.success(successMessage) && show)}
<NotificationContainer/>
everything is working fine but this notification container is being shown twice, i have been stuck in this for quite sometime now but can't understand why.any help is appriciated.
case UPDATE_EMAIL_SETTINGS_SUCCESS: {
return {
...state,
loader: false,
showEmailSuccess: false, // Add this line
settings: action.payload,
}
}
When a user tries to login, the Local state or Redux state should be updated. this.props.checkLogin() refers to the Redux store.
If the login is succesful, the Redux store should be updated.
Because this information is needed throughout the whole application.
If not succesful, the localstate should be updated with an error
message (a boolean which is called 'showError').
In the setup below, the results are always updated in the Redux store (which is not what I want, but I dont see any other solution yet). The main problem is that I can not catch an error in the checkLogin() of the component, if there is an error in the action.
// LOGIN COMPONENT (Code 1)
checkLogin(e){
e.preventDefault()
var username = e.target.elements.username.value
var password = e.target.elements.password.value
this.props.checkLogin(username, password)
}
// Redux action
export const checkLogin = (username, password) => async dispatch => {
axios.post('/api/login', {
username: username,
password: password
})
.then(res => {
const token = res.data.token;
localStorage.setItem('jwtToken', token);
setAuthorizationToken(token);
dispatch(setCurrentUser(jwt.decode(token)))
})
.catch(err => {
dispatch({
type: AUTH_ERROR,
payload: true
})
})
}
However, if there is an error in (Code 1), the Redux state is updated (with the AUTH_ERR action). I want to get rid of this action, as I only want it in local state. Because the boolean of an error login attempt should not be stored in Redux.
The only solution which I could think of is shown below (Code 2).
The POST-request has moved to the component itself (which is not nice in my opinion).
// LOGIN COMPONENT (Code 2)
checkLogin(e){
e.preventDefault()
var username = e.target.elements.username.value
var password = e.target.elements.password.value
axios.post('/api/login', {
username: username,
password: password
})
.then(res => {
this.props.checkLogin(username, password)
}
.catch(err => {
this.setState({
showError: true
})
})
}
// Redux action
export const checkLogin = (username, password) => async dispatch => {
const token = res.data.token;
localStorage.setItem('jwtToken', token);
setAuthorizationToken(token);
dispatch(setCurrentUser(jwt.decode(token)))
}
My main question is: what is the cleanest way of solving this? Is there some sort of guide which I can follow? The code (Code 2) works, but it definitely lacks design principles.
Another way of solving this could be something like this: use the first code and throw an error in the catch of the POST-request. Which is catched by the component, like this:
// LOGIN COMPONENT (Code 3)
checkLogin(e){
e.preventDefault()
var username = e.target.elements.username.value
var password = e.target.elements.password.value
this.props.checkLogin(username, password).catch(res => {
this.setState({
showError: true
})
})
}
// Redux action
export const checkLogin = (username, password) => async dispatch => {
axios.post('/api/login', {
username: username,
password: password
})
.then(res => {
const token = res.data.token;
localStorage.setItem('jwtToken', token);
setAuthorizationToken(token);
dispatch(setCurrentUser(jwt.decode(token)))
})
.catch(err => {
// Return an error here which is cacthed in the component
})
}
In the above code (Code 3), I can't see how to solve this. Is it possible to throw an error in the Redux action, which is then catched by the checkLogin() of the Login-component? Or should I complete take another path in solving this?
You have connected redux to manage the state of the application, why do you want to avoid storing an error in redux? A typical implementation of the react-redux (with redux-thunk middleware) authentication process is as follows.
actions.js
export const auth = (username, password) => {
dispatch(authStart())
axios.post('/api/login', {
username: username,
paswword: password
}).then(request => {
dispatch(authSuccess(response.authToken, response.userId))
}).catch(error => {
dispatch(authFail(error))
})
})
const authStart = () => {
return { type: 'AUTH_START'}
}
const authSuccess = (authToken, userId) => {
return { type: 'AUTH_SUCCESS', authToken: authToken, userId: userId }
}
const authFail = (error) => {
return { type: 'AUTH_FAIL', error: error }
}
reducer.js
const initialState = {
userId: null,
authToken: null,
error: null
loading: false
}
const authStart = (state, action) => {
return { ...state, loading: true, error: null }
}
const authSuccess = (state, action) => {
return {
...state,
loading: false,
authToken: action.authToken,
userId: actions.userId
}
}
const authStart = (state, action) => {
return { ...state, loading: false, error: error }
}
const authReducer = (state = initialState, action) => {
switch action.type:
case 'AUTH_START':
return authStart(state, action)
case 'AUTH_SUCCESS':
return authSuccess(state, action)
case 'AUTH_FAIL':
return authFail(state, action)
default:
return state
}
component.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { auth } from './actions.js'
class MyComponent extends Component {
checkLogin(e){
e.preventDefault()
var username = e.target.elements.username.value
var password = e.target.elements.password.value
this.props.signIn(username, password)
}
render() {
let content = <div>Login succeed. User id is {this.props.userId}</div>
if (this.props.loading) {
content = <div>Loading...</div>
}
if (this.props.error) {
content = <div>Error: {this.props.error}</div>
}
return <React.Fragment>{content}</React.Fragment>
}
}
const mapStateToProps = state => {
return {
error: state.auth.error,
loading: state.auth.loading,
userId: state.auth.userId
}
}
const mapDispatchToProps = dispatch => {
return {
signIn: (username, password) => dispatch(auth(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)
I have been working on authentication with my project. I have a REST api backend that serves JWT tokens. My front end stack is ReactJS, Redux, Axios and Redux Thunk.
My question is why when I submit my form it does not send any credentials?
But when I console log the action and payload on credChange it seems to be correct. Am I not setting the state somewhere?
Also, axios does not catch the 400 Bad Request error.
Here is my code:
AuthActions.js
export const credChange = ({ prop, value }) => {
return {
type: CRED_CHANGE,
payload: { prop, value },
};
};
export const logoutUser = () => {
return (dispatch) => {
dispatch({ type: LOGOUT_USER });
};
};
const loginSuccess = (dispatch, response) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: response.data.token,
});
};
const loginError = (dispatch, error) => {
dispatch({
type: LOGIN_USER_ERROR,
payload: error.response.data,
});
};
export const loginUser = ({ empNum, password }) => {
return (dispatch) => {
dispatch({ type: LOGIN_USER });
axios({
method: 'post',
url: 'http://127.0.0.1:8000/profiles_api/jwt/authTK/',
data: {
emp_number: empNum,
password,
},
})
.then(response => loginSuccess(dispatch, response))
.catch(error => loginError(dispatch, error));
};
};
AuthReducer.js
const INITIAL_STATE = {
empNum: '',
password: '',
empNumErr: null,
passwordErr: null,
authTK: null,
loading: false,
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case CRED_CHANGE:
return { ...state, [action.payload.prop]: action.payload.value };
case LOGIN_USER:
return {
...state,
...INITIAL_STATE,
loading: true,
};
case LOGOUT_USER:
return {
...state,
INITIAL_STATE,
};
case LOGIN_USER_SUCCESS:
return {
...state,
...INITIAL_STATE,
authTK: action.payload,
};
case LOGIN_USER_ERROR:
return {
...state,
...INITIAL_STATE,
empNumErr: action.payload.emp_number,
passwordErr: action.payload.password,
};
default:
return state;
}
};
LoginForm.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {
credChange,
loginUser,
logoutUser,
} from '../Actions';
class LoginForm extends Component {
constructor() {
super();
this.onFormSubmit = this.onFormSubmit.bind(this);
this.renderEmpNumErr = this.renderEmpNumErr.bind(this);
this.empNumChange = this.empNumChange.bind(this);
this.passwordChange = this.passwordChange.bind(this);
}
onFormSubmit() {
const { empNum, password } = this.props;
this.props.loginUser({ empNum, password });
}
empNumChange(text) {
this.props.credChange({ prop: 'empNum', value: text.target.value });
}
passwordChange(text) {
this.props.credChange({ prop: 'password', value: text.target.value });
}
renderEmpNumErr() {
if (this.props.empNumErr) {
return (
<p>
{this.props.empNumErr}
</p>
);
}
return null;
}
render() {
return (
<div>
<form onSubmit={this.onFormSubmit}>
<label htmlFor="numberLabel">Employee Number</label>
<input
id="numberLabel"
type="password"
value={this.props.empNum}
onChange={this.empNumChange}
/>
<label htmlFor="passLabel">Password</label>
<input
id="passLabel"
type="password"
value={this.props.password}
onChange={this.passwordChange}
/>
<button type="submit">Login</button>
</form>
{this.renderEmpNumErr()}
</div>
);
}
}
const mapStateToProps = ({ counter }) => {
const {
empNum,
password,
loading,
empNumErr,
passwordErr,
authTK,
} = counter;
return {
empNum,
password,
loading,
empNumErr,
passwordErr,
authTK,
};
};
export default connect(mapStateToProps, { credChange, loginUser, logoutUser })(LoginForm);
After Submitting form with credentials
The console says:
POST XHR http://127.0.0.1:8000/profiles_api/jwt/authTK/ [HTTP/1.0 400 Bad Request 5ms]
And the POST request Raw Data is blank, therefore no credentials were sent.
{"emp_number":["This field is required."],"password":["This field is required."]}
EDIT
If there is any other information I can provide please say so but I think this should be sufficient.
Looks like empNum and password aren't getting set in the state. This is because the action object returned by credChange doesn't get dispatched, so the reducer never get called:
// dispatch calls the reducer which updates the state
dispatch(actionCreator())
// returns an action object, doesn't call reducer
actionCreator()
You can dispatch actions automatically by calling a bound action creator:
// calls the reducer, updates the state
const boundActionCreator = () => {dispatch(actionCreator())}
// call boundActionCreator in your component
boundActionCreator()
mapDispatchToProps can be used to define bound action creators (to be passed as props):
const mapDispatchToProps = (dispatch) => {
return {
credChange: ({ prop, value }) => {dispatch(credChange({prop, value})},
loginUser: ({ empNum, password }) => {dispatch(loginUser({empNum, password})},
logoutUser: () => {dispatch(logoutUser()},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
This should solve the state update issue, allowing props that read from state (empNumber, password, etc.) to update as well.