I have a already built React form, which works fine expect reset functionality. It has used uncontrolled components bit different way. I am looking for what I need to follow, change the code to achieve my goal.
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
import * as React from "react";
import WidgetComponent from './../../lib/WidgetComponent';
import jQuery from 'jquery';
import InputListComponent from './components/InputListComponent';
import FormInputComponent from './components/FormInputComponent';
import formTextInputComponent from './components/formTextInputComponent';
import FormInputPasswordComponent from './components/FormInputPasswordComponent';
import FormSelectComponent from './components/FormSelectComponent';
import SubmitBtnListComponent from './components/SubmitBtnListComponent';
import SubmitBtnComponent from './components/SubmitBtnComponent';
import ErrorListBox from './components/ErrorListBox';
import EmailPromptModal from './components/EmailPromptModal';
import formHandlerInterfaceFactory from './lib/formHandlerInterface';
import formValidator from './lib/formValidators';
import {generateJQueryAjaxConfigFromPlaceholders} from './../../lib/GenerateJQueryAjaxConfig';
import './styles/registration-form.scss';
export default class ControlPanelCreateAccounts extends WidgetComponent {
constructor(props) {
super(props);
this.state = {
form: {
firstName: "",
lastName: "",
username: "",
password: "",
confirmPassword: "",
email: "",
phone: "",
accessLevel: -1,
},
userRoles: [],
validInputs: {
firstName: false,
lastName: false,
username: false,
password: false,
confirmPassword: false,
email: false,
phone: false,
accessLevel: false,
},
defaultValue: {
firstName: "",
lastName: "",
username: "",
password: "",
confirmPassword: "",
email: "",
phone: "",
accessLevel: -1,
},
errors: [],
submitService: null,
userRoleService: null,
newUserId: null,
};
this.onFormInputChange = this.onFormInputChange.bind(this);
this.onServicesCalled = this.onServicesCalled.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
this.formElementInvalid = this.formElementInvalid.bind(this);
this.formElementValid = this.formElementValid.bind(this);
this.postWidgetLoad = this.postWidgetLoad.bind(this);
this.createUserRequest = this.createUserRequest.bind(this);
this.createUserRoleRequest = this.createUserRoleRequest.bind(this);
this.onResetReceived = this.onResetReceived.bind(this);
this.onFormInputReset = this.onFormInputReset.bind(this);
}
onResetReceived(){
console.log('onResetReceived');
let newState = Object.assign(this.state.form, {
firstName : "",
});
this.setState(newState);
console.log(this.state.form);
}
postWidgetLoad(widget) {
EmailPromptModal.service = widget.services[2];//??
let submitService = widget.services[1];//1
let userRoleService = widget.services[2];//2
//this.storeState({ submitService });
let newState = Object.assign(this.state, {
submitService: submitService,
userRoleService: userRoleService
});
this.setState(newState);
}
validate() {
console.log('validating pre-submit');
let errors = Object.keys(this.state.validInputs).reduce((accum, current) => {
console.log('state of accumulator is: ');
console.log(accum);
console.log('current iteration is: ' + current);
//console.log('password and reType passwords are : ');
//console.log(this.state.form.password + " :: " + this.state.confirmPassword );
if (this.state.validInputs[current] === false) {
console.log('current input is invalid');
this.validate = this.validate.bind(this);
if (current === 'firstName') {
accum.push('The first name field is either empty or contains invalid characters');
}
if (current === 'lastName') {
accum.push('The last name field is either empty or contains invalid characters');
}
if (current === 'email') {
accum.push('The email field is empty or is not a valid email address');
}
if (current === 'phone') {
accum.push('The phone field is empty or is not a valid phone number');
}
if (current === 'password') {
accum.push('The password field is empty or contain less than 5 characters or contain invalid character');
}
if (current === 'confirmPassword') {
accum.push('The passwords mismatched');
}
if (current === 'accessLevel') {
accum.push('You must select a accessLevel from the drop-down menu.');
}
}
return accum;
}, []);
console.log('final error list looks like: ');
console.log(errors);
this.storeState({
errors: errors
});
return errors.length === 0;
}
onServicesCalled() {
let response = arguments[0][0].data;
let roleList = [];
if (response) {
response.map(element => {
roleList.push({val: element.id, text: element.role_name});
});
}
let newState = Object.assign(this.state, {
userRoles: roleList
});
this.setState(newState);
}
onFormInputChange(ev, legend) {
let value = ev.target.value;
let form = this.state.form;
form[legend] = value;
this.storeState({
form
});
formElementInvalid(elem) {
let name = elem.name;
let stateUpdateObj = this.state.validInputs;
stateUpdateObj[name] = false;
this.storeState({validInputs: stateUpdateObj});
if (name !== 'status') {
elem.classList.add('input-error');
} else {
document.getElementById('status-error-field').classList.add('visible');
}
}
formElementValid(elem) {
let name = elem.name;
let stateUpdateObj = this.state.validInputs;
stateUpdateObj[name] = true;
this.storeState({validInputs: stateUpdateObj});
if (name !== 'status') {
elem.classList.remove('input-error');
} else {
document.getElementById('status-error-field').classList.remove('visible');
}
}
onFormSubmit() {
if (this.validate()) {
console.log("validate got passed");
console.log(this.state.form);
var id;
// match password fields
if (this.state.form.password !== this.state.form.confirmPassword) {
let stateUpdateObj = this.state.validInputs;
stateUpdateObj['confirmPassword'] = false;
this.storeState({validInputs: stateUpdateObj});
this.onFormSubmit();
} else {
jQuery.when(this.createUserRequest()).done((r) => {
console.log("submit for createUser is success reload!");
console.log(r);
id = r.data.id;
jQuery.when(this.createUserRoleRequest(id)).done((r) => {
console.log("submit for createUserRole is success reload!");
console.log(r);
if(r.data.wasSuccessful){
console.log("create UserRole is successful, So reload the table ");
// do page refresh here
window.pubsub.publish('isp.reload-control-users', {});
//reset the form
console.log("reset the form contents");
this.onResetReceived();
}
}).fail((xhr, status, error) => {
console.log(status);
console.error(error);
alert('An error occured while submitting this request, if this issue persists please contact support.');
});
let newState = Object.assign(this.state, {
newUserId: r.data.id
});
this.setState(newState);
}).fail((xhr, status, error) => {
console.log(status);
console.error(error);
alert('An error occured while submitting this request, if this issue persists please contact support.');
});
}
}
}
//create a record in is_auth_roles table
createUserRoleRequest(id) {
let config = generateJQueryAjaxConfigFromPlaceholders(this.state.userRoleService, {'userId': id});
config.headers['Content-Type'] = 'application/json';
config.headers['Accept'] = '*/*';
config.data = JSON.stringify({
'roleId': this.state.form.accessLevel,
'type': 'add'
});
console.log("submit config of createUserRoleRequest() is: ");
console.log(config);
return jQuery.ajax(config);
}
createUserRequest() {
let config = generateJQueryAjaxConfigFromPlaceholders(this.state.submitService, {});
config.headers['Content-Type'] = 'application/json';
config.headers['Accept'] = '*/*';
config.data = JSON.stringify({
firstName: this.state.form.firstName,
lastName: this.state.form.lastName,
username: this.state.form.username,
phone: this.state.form.phone,
password: this.state.form.password,
confirmPassword: this.state.form.confirmPassword,
email: this.state.form.email,
accessLevel: this.state.accessLevel
});
console.log("submit config is: ");
console.log(config);
return jQuery.ajax(config);
}
render() {
return (
<div className="registration-form">
<h3 className="component-title"><i className="fa fa-table" aria-hidden="true"></i> User <span> Registration</span></h3><br/>
<InputListComponent>
{/*onValid={this.formElementValid} />*/}
<formTextInputComponent legend="firstName" label="First Name" placeholder="First Name" onChange={this.onFormInputChange} validator={formValidator.nameValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.firstName} value={ this.state.value}
onValid={this.formElementValid} />
<FormInputComponent legend="lastName" label="Last Name" placeholder="Last Name" onChange={this.onFormInputChange} validator={formValidator.nameValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.lastName}
onValid={this.formElementValid}/>
<FormInputComponent legend="username" label="User Name" placeholder="User Name" onChange={this.onFormInputChange} validator={formValidator.nameValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.username}
onValid={this.formElementValid}/>
<FormInputPasswordComponent legend="password" label="Password" placeholder="Password" onChange={this.onFormInputChange} validator={formValidator.passwordValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.password}
onValid={this.formElementValid}/>
<FormInputPasswordComponent legend="confirmPassword" label="Confirm Password" placeholder="Confirm Password" onChange={this.onFormInputChange} validator={formValidator.passwordValidator} default = {this.state.defaultValue.confirmPassword}
onInvalid={this.formElementInvalid} onValid={this.formElementValid}/>
<FormInputComponent legend="email" label="Email Address" placeholder="Email" onChange={this.onFormInputChange} validator={formValidator.emailValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.email}
onValid={this.formElementValid}/>
<FormInputComponent legend="phone" label="Phone Number" placeholder="Phone Number" onChange={this.onFormInputChange} validator={formValidator.phoneValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.phone}
onValid={this.formElementValid}/>
<FormSelectComponent legend="accessLevel" data={this.state.userRoles} onChange={this.onFormInputChange} validator={formValidator.statusValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.accessLevel}
onValid={this.formElementValid}/>
</InputListComponent>
<ErrorListBox errorList={this.state.errors}/>
<button className="dataTable-modal-btn click-btn" onClick={this.onFormSubmit}>CREATE USER</button>
</div>
);
}
}
window.ControlPanelCreateAccounts = ControlPanelCreateAccounts;
window.CurrentWidget = window.ControlPanelCreateAccounts;
this is formInputComponent code
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
const FormInputComponent = (props) => {
const onChangeHandler = (ev) => {
if(props.validator(ev.target.value)) {
props.onChange(ev, props.legend);
props.onValid(ev.target);
} else {
props.onInvalid(ev.target);
}
};
console.log('props.defaultValue');
console.log(props.legend);
console.log(props.default);
console.log(props.value);
return (
<div className="form-row">
<label>{props.label}</label><br />
<input name={props.legend} type="text" placeholder={props.placeholder} onChange={onChangeHandler} defaultValue={props.default || ''} value={props.value}/>
</div>
);
};
FormInputComponent.propTypes = {
legend: React.PropTypes.string,
label: React.PropTypes.string,
placeholder: React.PropTypes.string,
onChange: React.PropTypes.func,
validator: React.PropTypes.func,
onInvalid: React.PropTypes.func,
onValid: React.PropTypes.func,
default: React.PropTypes.string,
};
export default FormInputComponent;
If you want setState inside of onResetReceived to reset the form, you'll need to set the value prop of each form field. The default prop gets sent to FormInputComponent as the defaultValue of the input, but you can also see it accepts a value={props.value} as well (even though value is not defined in its PropTypes. From the parent set
<FormInputComponent value={this.state.form.firstName} ... />
This will ensure changing this.state.form via setState will update each form field.
Related
I have an input component where I pass a hasError prop and display an error message below the input field if the value of input is empty. I have a function where it will validate the entered value then it will return an object, and that function will be pass as a parameter in my custom hook. How can I make my hasError dynamically? Now, when I add a new input element I will add a new key-value pair on the hasError object. How can I prevent that?
import React from 'react';
import { useInput } from '#/Shared/hooks';
import { Button, FormInput } from '#/Shared/components';
const PersonForm = () => {
const initialValues = {
firstName: '',
lastName: '',
email: '',
};
const initialTouched = {
firstName: false,
lastName: false,
email: false,
};
const validateValue = value => {
return {
firstName: value.firstName.trim() !== '',
lastName: value.lastName.trim() !== '',
email: value.email.trim() !== '' && value.email.includes('#'),
};
};
const {
value,
valueIsValid,
reset,
hasError,
onChangeInputHandler,
onBlurInputHandler,
} = useInput(initialValues, initialTouched, validateValue);
let formIsValid = false;
if (!Object.values(valueIsValid).filter(e => !e).length) {
formIsValid = true;
}
const handleSubmitPerson = e => {
e.preventDefault();
if (Object.values(valueIsValid).filter(e => !e).length) return;
reset();
};
return (
<form onSubmit={handleSubmitPerson}>
<FormInput
label="First Name"
name="firstName"
id="firstName"
value={value.firstName}
onChange={onChangeInputHandler}
onBlur={onBlurInputHandler}
isInvalid={hasError.firstName}
errorMessage="First name must not be empty."
/>
<FormInput
label="Last Name"
name="lastName"
id="lastName"
value={value.lastName}
onChange={onChangeInputHandler}
onBlur={onBlurInputHandler}
isInvalid={hasError.lastName}
errorMessage="Last name must not be empty."
/>
<FormInput
label="Email Address"
name="email"
id="email"
value={value.email}
onChange={onChangeInputHandler}
onBlur={onBlurInputHandler}
isInvalid={hasError.email}
errorMessage="Invalid email address!"
/>
<div className="mt-6">
<Button type="submit" disabled={!formIsValid}>
Submit
</Button>
</div>
</form>
);
};
useInput Hook
import { useState } from 'react';
const useInput = (initialValues, initialTouched, validateValue) => {
const [value, setValue] = useState(initialValues);
const [isTouched, setIsTouched] = useState(initialTouched);
const valueIsValid = validateValue(value);
const hasError = {
firstName: !valueIsValid.firstName && isTouched.firstName,
lastName: !valueIsValid.lastName && isTouched.lastName,
email: !valueIsValid.email && isTouched.email,
};
const onChangeInputHandler = e => {
setValue({
...value,
[e.target.name]: e.target.value,
});
};
const onBlurInputHandler = e => {
setIsTouched({
...isTouched,
[e.target.name]: true,
});
};
const reset = () => {
setValue({
...initialValues,
});
setIsTouched({
...initialTouched,
});
};
return {
value,
valueIsValid,
hasError,
reset,
onChangeInputHandler,
onBlurInputHandler,
};
};
I have this Formik form for authentication which can switch from login (by default) to signup form using switch button. Using Formik and yup validation schema, the form first check the fields' values on change and before submitting. On submit, I am trying to have another value check from the server side and to show error messages on top of each field (at the same place as the client side error messages provided by Formik and Yup). When the 'submit' button is clicked and in case of a server error after validation, the state of my Redux 'authReducer' is updated with 'errors'' object inside 'data' property. Through local state, then I create a variable 'errorServer' which is an object created to store for each input (as key), the related server error's message (as value). Then, using this object, I'm trying to show the error message(s) on top of field(s) concerned (I tried both Formik methods 'setErrors' and 'setStatus' to do so). But, in the best case, this error message is only appearing after a second click on the 'submit' button and I don't know how to solve this problem... Can anyone provide me some help? Many thanks!
Server side
auth.controller.js
const { findUserPerUsername, findUserPerEmail} = require('../queries/users.queries');
const { createUser } = require('../queries/users.queries');
const { check, validationResult } = require('express-validator');
// Field value validation before signup
exports.validate = (method) => {
switch (method) {
case 'signup': {
return [
check('name')
.exists()
.withMessage('Enter your name.'),
check('username')
.exists()
.withMessage('Enter a username.')
.isAlphanumeric()
.withMessage('Username must contain only letters and numbers.')
.custom(value => {
return findUserPerUsername(value).then(user => {
if (user) {
return Promise.reject('Username already in use.');
}
})
}),
check('email')
.exists()
.withMessage('Enter an email address.')
.isEmail()
.withMessage('A valid email address is required.')
.custom(value => {
return findUserPerEmail(value).then(user => {
if (user) {
return Promise.reject('Email address already in use.');
}
})
}),
check('password')
.exists()
.withMessage('Enter a password.')
.custom(value => {
const pswRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[##$!%*?&-])[A-Za-z\d##$!%*?&-]{8,}$/;
if (pswRegex.test(value) === false) {
return Promise.reject('Password must contain 8 Characters, One Uppercase, One Lowercase, One Number and One Special Case Character')
} else {
return Promise.resolve();
}
})
]
}
case 'login': {
return [
check('email')
.exists()
.withMessage('Enter an email address.')
.isEmail()
.withMessage('A valid email address is required'),
check('password')
.exists()
.withMessage('Enter a password.')
.custom(value => {
const pswRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[##$!%*?&-])[A-Za-z\d##$!%*?&-]{8,}$/;
if (pswRegex.test(value) === false) {
return Promise.reject('Password must contain 8 Characters, One Uppercase, One Lowercase, One Number and One Special Case Character')
} else {
return Promise.resolve();
}
})
]
}
}
}
exports.signup = async (req, res, next) => {
try {
const body = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.status(400).send({
success: false,
errors: errors.array()
});
next();
} else {
const user = await createUser(body);
req.login(user);
res.status(200).send({
user: user,
success: true,
message: 'User successfully registered.'
})
next();
}
} catch(e) {
next(e);
}
}
exports.login = async (req, res, next) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.status(400).send({
success: false,
errors: errors.array()
});
next();
} else {
const { email, password } = req.body;
const user = await findUserPerEmail(email);
if (user) {
const match = await user.comparePassword(password);
if (match) {
req.login(user);
res.status(200).send({
user: user,
success: true,
message: 'User successfully logged in.'
});
next();
} else {
res.status(401).send({
success: false,
errors: {
msg: 'Sorry, that password is not right. Please try again or reset your password.',
param: 'password',
location: 'body'
}
});
next();
}
} else {
res.status(401).send({
success: false,
errors: {
msg: 'Sorry, we could not find an account with that email. Please try again or sign up.',
param: 'email',
location: 'body'
}
});
next();
}
}
} catch(e) {
next(e);
}
}
exports.logout = (req, res, next) => {
req.logout();
res.status(200).send({
success: true,
message: "User successfully logged out."
})
next();
}
Client side
auth.config.js
import axios from 'axios';
const API_URL = 'http://localhost:3001/api/auth/'
const signup = ({ name, username, email, password }) => {
return axios.post(API_URL + 'signup', {
name,
username,
email,
password
});
};
const login = ({ email, password }) => {
return axios
.post(API_URL + 'login', {
email,
password
})
.then((res) => {
return res.data;
});
};
const logout = () => {
return axios.get(API_URL + 'logout').then((res) => {
return res.data;
});
};
const getCurrentUser = () => {
/* return JSON.parse(localStorage.getItem('user')); */
}
const AuthConfig = {
signup,
login,
logout,
getCurrentUser
}
export default AuthConfig;
Redux store:
actions.js
import AuthConfig from '../config/auth.config';
export const SIGNUP_SUBMIT = "signup submit";
export const SIGNUP_SUCCESS = "signup success";
export const SIGNUP_ERROR = "signup error";
export const LOGIN_SUBMIT = "login submit";
export const LOGIN_SUCCESS = "login success";
export const LOGIN_ERROR = "login error";
export const LOGOUT = "logout";
export const signup = (name, username, email, password) => (dispatch) => {
return AuthConfig.signup(name, username, email, password).then(
(response) => {
dispatch({
type: SIGNUP_SUCCESS,
payload: response.data
});
},
(error) => {
dispatch({
type: SIGNUP_ERROR,
error: error.response.data
});
}
);
};
export const login = (email, password) => (dispatch) => {
return AuthConfig.login(email, password).then(
(response) => {
dispatch({
type: LOGIN_SUCCESS,
payload: response.data
});
},
(error) => {
dispatch({
type: LOGIN_ERROR,
error: error.response.data
});
}
);
};
export const logout = () => (dispatch) => {
AuthConfig.logout().then(
(response) => {
dispatch({
type: LOGOUT,
payload: response.message
})
}
);
};
reducers.js
import {
SIGNUP_SUBMIT,
SIGNUP_SUCCESS,
SIGNUP_ERROR,
LOGIN_SUBMIT,
LOGIN_SUCCESS,
LOGIN_ERROR,
LOGOUT
} from "./actions";
const initialState = { isLoggedIn: false, data: {} }
export const authReducer = (state = initialState, action) => {
const { type, payload, error } = action;
switch (type) {
case SIGNUP_SUBMIT:
return {
...state,
isLoggedIn: false,
};
case SIGNUP_SUCCESS:
return {
...state,
isLoggedIn: true,
data: payload
};
case SIGNUP_ERROR:
return {
...state,
isLoggedIn: false,
data: error
};
case LOGIN_SUBMIT:
return {
...state,
isLoggedIn: false,
};
case LOGIN_SUCCESS:
return {
...state,
isLoggedIn: true,
data: payload
};
case LOGIN_ERROR:
return {
...state,
isLoggedIn: false,
data: error
};
case LOGOUT:
return {
...state,
isLoggedIn: false,
data: null
};
default: {
return state;
}
}
};
export default authReducer;
Form.js
import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { Formik, useFormikContext } from 'formik';
import * as Yup from 'yup';
/* import { SignupSchema, LoginSchema /* YupSchema * } from './YupSchema'; */
import Input from './Input';
import { signup, login } from '../../store/actions';
import { Eye, EyeSlash, Lock, MedalStar, Personalcard, Sms, User } from 'iconsax-react';
import './Form.css';
const Logger = () => {
const formik = useFormikContext();
useEffect(() => {
console.group("Formik State");
console.log("status", formik.status);
console.log("values", formik.values);
console.log("errors", formik.errors);
console.log("touched", formik.touched);
console.log("isSubmitting", formik.isSubmitting);
console.log("isValidating", formik.isValidating);
console.log("submitCount", formik.submitCount);
console.groupEnd();
}, [
formik.status,
formik.values,
formik.errors,
formik.touched,
formik.isSubmitting,
formik.isValidating,
formik.submitCount
]);
return null;
};
const ServerValidation = () => {
const { values, /* submitForm, */ } = useFormikContext();
useEffect(() => {
if (values.username === 'JDope99' || values.email === 'jdoe#gmail.com') {
/* submitForm(); */
/* console.log('Username or email already in use.'); */
/* alert(JSON.stringify('Username or email already in use.')); */
}
}, [values]);
return null;
};
const Form = () => {
const authServerErrors = useSelector(state => state.authReducer.data.errors);
console.log(authServerErrors);
const [errorServer, setErrorServer] = useState('');
console.log(errorServer);
const [isSignupForm, setIsSignupForm] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const handleShowPassword = () => setShowPassword(!showPassword);
useEffect(() => {
if (authServerErrors === undefined) {
return
} else {
console.log(authServerErrors);
if (Array.isArray(authServerErrors)) {
let fields = authServerErrors.map(el => el.param);
let msgs = authServerErrors.map(el => el.msg);
if (fields !== [] && msgs !== []) {
let errorObj;
fields.reduce(function(obj, key, index) {
obj[key] = msgs[index]
return errorObj = obj
}, {});
setErrorServer(errorObj);
};
} else {
let field = authServerErrors.param;
let msg = authServerErrors.msg;
let error = {};
error[field] = msg;
setErrorServer(error);
}
}
}, [authServerErrors]);
const switchForm = () => {
setIsSignupForm(!isSignupForm);
setShowPassword(false);
}
const initialValues = {
name: '',
username: '',
email: '',
password: ''
}
const dispatch = useDispatch();
const navigate = useNavigate(); // Will be used to redirect user in case of no server error to /Home
const YupSchema = Yup.object().shape({
name: Yup.string().when('isSignupForm', {
is: true,
then: Yup
.string()
.min(2, 'Too short')
.max(20, 'Too long')
.required('Required'),
otherwise: Yup.string().min(2, 'Too short').max(20, 'Too long')
}),
username: Yup.string().when('isSignupForm', {
is: true,
then: Yup
.string()
.min(2, 'Too short')
.max(20, 'Too long')
.required('Required'),
otherwise: Yup.string().min(2, 'Too short').max(20, 'Too long')
}),
email: Yup
.string()
.email('Valid email required')
.required('Required'),
password: Yup
.string()
.matches(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##\$%\^&\*])(?=.{8,})/,
"Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and One Special Case Character"
)
.required('Required')
})
return (
<div className="container">
<Formik
initialValues={ initialValues }
validationSchema= { YupSchema }
onSubmit={async (values, actions) => {
try {
if (isSignupForm) {
await dispatch(signup(values));
/* errors.setErrors({
name: errorServer.name,
username: errorServer.username,
email: errorServer.email,
password: errorServer.password
})
console.log(errors); */
} else {
await dispatch(login(values));
}
actions.setStatus({
name: errorServer.name || '',
username: errorServer.username || '',
email: errorServer.email || '',
password: errorServer.password || ''
});
} catch (error) {
console.log(error);
}
}}
>
{({ handleChange, handleBlur, handleReset, handleSubmit, values, errors, status, isValid, dirty }) => (
<form
id="auth-form"
className="d-flex flex-column justify-content-start align-items-start py-3"
onChange={ handleChange }
onBlur={ handleBlur }
onReset={ handleReset }
onSubmit= { handleSubmit }
>
<Logger />
{ isSignupForm ? (
<>
<h2>Sign Up</h2>
<p className="text-lg">Welcome to our website! We hope you will enjoy being part of our community.</p>
<div className="input-box mb-3 w-100">
<Input
label="Name"
type="text"
name="name"
className="form-control"
helpText="Please enter your full name."
icon={<Personalcard size="20" color="#666664" variant="Bold" /* className="input-icon" */ />}
errors={errors.name}
value={values.name}
status={ status !== undefined ? status.name : ''}
/>
</div>
<div className="input-box mb-3 w-100">
<Input
label="Username"
type="text"
name="username"
className="form-control"
helpText="Must contain only letters and numbers"
icon={<User size="20" color="#666664" variant="Bold" /* className="input-icon" */ />}
errors={errors.username}
value={values.username}
status={ status !== undefined ? status.username : ''}
/>
</div>
</>
) : (
<>
<h2>Log In</h2>
<p className="text-lg">We are pleased to have you back.</p>
</>
)}
<div className="input-box mb-3 w-100">
<Input
label="Email"
type="text"
name="email"
className="form-control"
helpText="example#email.com"
icon={<Sms size="20" color="#666664" variant="Bold" /* className="input-icon" */ />}
errors={errors.email}
value={values.email}
status={ status !== undefined ? status.email : ''}
/>
</div>
<div className="input-box mb-3 w-100">
<Input
label="Password"
type={ showPassword ? "text" : "password"}
name="password"
/* className="form-control" */
helpText="Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and One Special Case Character"
icon={<Lock size="20" color="#666664" variant="Bold" /* className="input-icon" */ />}
toggle={ showPassword ? <Eye size="20" color="#000000" className="toggle-icon" onClick={ handleShowPassword } /> : <EyeSlash size="20" color="#000000" className="toggle-icon" onClick={ handleShowPassword } /> }
errors={errors.password}
value={values.password}
status={ status !== undefined ? status.password : ''}
/>
</div>
{ isSignupForm ? (
<div className="mt-1">
<p>By clicking "Sign Up" you agree to our Customer Terms and Privacy Policy.</p>
</div>
) : null}
<div className="d-flex flex-row mt-1">
<button type="submit" className="btn btn-green me-3" disabled={isSignupForm ? !(isValid && dirty) : null }>
{ isSignupForm ? 'Sign Up' : 'Log In' }
</button>
<button type="reset" className="btn btn-outline-black">
Reset
</button>
</div>
<div className="mt-2">
{ isSignupForm ? (
<p>Already have an account? <button type="button" className="link" onClick={() => { switchForm(); handleReset() } }>Log In</button></p>
)
:
(
<p>New to InkIt? <button type="button" className="link" onClick={() => { switchForm(); handleReset() } }>Sign Up</button></p>
)
}
</div>
<ServerValidation />
</form>
)}
</Formik>
</div>
);
};
export default Form;
Input.js
import React, { useState } from 'react';
import { useField } from 'formik';
import { TickSquare } from 'iconsax-react';
const Input = ({ label, helpText, icon, toggle, errors, status, ...props}) => {
const [field, meta, helpers] = useField(props);
console.log({ field, meta, helpers });
// Show inline feedback if EITHER
// - the input is focused AND value is longer than 2 characters
// - or, the has been visited (touched === true)
const [didFocus, setDidFocus] = useState(false);
const handleFocus = () => setDidFocus(true);
const showInputFeedback = (!!didFocus && field.value.trim().length > 2) || meta.touched;
return (
<div className={`form-control px-3 py-2 ${showInputFeedback ? (meta.error ? 'invalid' : 'valid') : ""}`}>
<div className="label-box d-flex flex-row justify-content-between align-items-center">
<label htmlFor={props.name}>{label}</label>
{showInputFeedback ? (
<div className="feedback text-sm">
{ meta.error ? meta.error : status ? status : <TickSquare size="20" color="#06d6a0" variant="Bold" />}
</div>
)
: null}
</div>
<div className="d-flex flex-row flex-nowrap">
<span className="input-icon icon-left">
{icon}
</span>
<input className={ toggle ? "form-control input-password" : "form-control" } autoComplete="off" onFocus={ handleFocus } {...field} {...props} />
{toggle ? (
<span className="input-icon icon-right">
{toggle}
</span>
)
: null
}
</div>
<div className="help-text text-xs">
{helpText}
</div>
</div>
);
}
export default Input;
Chrome console.log:
enter image description here
i'm new at React, i want to ask about contidional recndering, i'm making project about sending message, and i use validation to check all field is not empty, when one field is empty it should show error message that message not send. I using if-else to render the error message, but it doesn't work.
Here i add my code
....
export default class Message extends React.Component {
constructor(props){
super(props);
this.state = {
isLoggedIn: SystemStore.isLoggedIn(),
profile: ProfileStore.getProfile(),
fullName: SystemStore.systemUser().fullName,
site: '',
email: '',
phone: '',
subject: '',
description: '',
type: '',
errorMessage: '',
errorDialog: '',
isSubmited: false,
successMessage: '',
submitting: false
};
this.clearForm = this.clearForm.bind(this);
this.handleProfileChange = this.handleProfileChange.bind(this);
this.handleSubjectChange = this.handleSubjectChange.bind(this);
this.handleMessageChange = this.handleMessageChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleSubmitComplete = this.handleSubmitComplete.bind(this);
this.handleSubmitError = this.handleSubmitError.bind(this);
}
componentDidMount(){
ProfileStore.addProfileChangeListener(this.handleProfileChange);
if(!this.state.profile){
ProfileActions.reload()
}
MessageStore.addSubmitMessageChangeListener(this.handleSubmitComplete);
MessageStore.addSubmitMessageFailChangeListener(this.handleSubmitError);
}
componentWillUnmount(){
ProfileStore.removeProfileChangeListener(this.handleProfileChange);
MessageStore.removeSubmitMessageChangeListener(this.handleSubmitComplete);
MessageStore.removeSubmitMessageFailChangeListener(this.handleSubmitError);
}
render(){
return(
<Layout>
<div className='hs-dashboard row'>
<div className='col-md-12'>
<div className='col-xs-12 col-sm-6 col-md-5'>
<div className='col-xs-12 hs-message-form'>
<div className='row hs-message-form-head'>
<div className='hs-message-form-logo-container'>
<img className='col hs-message-form-logo' src='../../images/gii-logo-black.png'/>
<text className='hs-message-form-logo-label'>{T.translate('gii')}</text>
</div>
<div className='hs-message-form-label'>
{ T.translate('message.title') }
</div>
<div className='hs-message-form-label-1'>
{ T.translate('message.subtitle') }
</div>
</div>
<div className='row hs-message-form-body'>
<form className='hs-message-form-body-content'>
<label>
{ T.translate('message.type') }
</label>
<select
id="subject"
value={ this.state.subject }
onChange={ this.handleSubjectChange }
className="form-control"
required="true"
>
<option value="">{ T.translate('placeholder.selectSubject') }</option>
<option value="PRAYER">{ T.translate('message.pray') }</option>
<option value="ADDRESS">{ T.translate('message.address') }</option>
<option value="VISIT">{ T.translate('message.visit') }</option>
</select>
<label>
{T.translate('message.message')}
</label>
<textarea
type="text"
id="description"
className="form-control"
width=''
placeholder={ T.translate('placeholder.message') }
onChange={ this.handleMessageChange }
value={ this.state.description }
required
/>
{ this.state.errorDialog &&
<div className='hs-message-empty'>
{ this.state.errorDialog }
</div>
}
{ this.state.isSubmited === true ?
<div className='hs-message-success'>
{ this.state.successMessage }
</div> :
<div className='hs-message-error'>
{ this.state.errorMessage }
</div>
}
<LaddaButton
loading={ this.state.submitting }
onClick={ this.handleSubmit }
data-spinner-size={ 30 }
data-style={ SLIDE_RIGHT }
>
{ T.translate('action.send') }
</LaddaButton>
</form>
</div>
</div>
</div>
</div>
</div>
</Layout>
)
}
clearForm(){
this.setState({ subject: '', description: '' });
}
handleProfileChange(){
this.setState({
site: ProfileStore.getProfile().primarySite.name,
email: ProfileStore.getProfile().emailAddresses[0].email,
phone: ProfileStore.getProfile().contactNumbers[0].countryCode + ProfileStore.getProfile().contactNumbers[0].number
});
}
handleSubjectChange(evt){
this.setState({ subject: evt.target.value }, () => {
if(this.state.subject === 'PRAYER') {
this.setState({ type: 'REQUEST' });
} else if(this.state.subject === 'ADDRESS') {
this.setState({ type: 'INFORMATION' });
} else if(this.state.subject === 'VISIT'){
this.setState({ type: 'REQUEST' });
}
});
}
handleMessageChange(evt){
this.setState({ description: evt.target.value });
}
handleSubmit(evt) {
evt.preventDefault();
var errorDialog;
if(this.state.subject === ''){
errorDialog = 'Error:' + T.translate('msg.subjectRequired');
} else if(this.state.description === ''){
errorDialog = 'Error:' + T.translate('msg.mailDescriptionRequired');
}
this.setState({errorDialog: errorDialog});
this.handleProfileChange();
this.handleSubjectChange(evt);
this.handleMessageChange(evt);
var messageInfo = {
fullName: this.state.fullName,
site: this.state.site,
email: this.state.email,
phone: this.state.phone,
subject: this.state.subject,
description: this.state.description,
type: this.state.type
};
this.setState({ submitting: true }, () => {
MessageActions.sendMessage(messageInfo);
});
console.log(this.state.isSubmited);
}
handleSubmitComplete(){
this.setState({
submitting: false,
isSubmited: true,
errorMessage: null,
successMessage: T.translate('msg.mailSent')
});
this.clearForm();
}
handleSubmitError(){
this.setState({
submitting: false,
isSubmited: false,
errorMessage: T.translate('msg.mailSentFailed'),
successMessage: null
});
}
}
//updated code
This is my store.js
....
var MessageStore = assign({}, EventEmitter.prototype, {
emitSubmitMessageChange: function(){
this.emit(SUBMIT_MESSAGE);
},
addSubmitMessageChangeListener: function(callback){
this.on(SUBMIT_MESSAGE, callback);
},
removeSubmitMessageChangeListener: function(callback){
this.removeListener(SUBMIT_MESSAGE, callback);
},
emitSubmitMessageFailChange: function() {
this.emit(SUBMIT_MESSAGE_FAILED);
},
addSubmitMessageFailChangeListener: function(callback) {
this.on(SUBMIT_MESSAGE_FAILED, callback);
},
removeSubmitMessageFailChangeListener: function(callback) {
this.removeListener(SUBMIT_MESSAGE_FAILED, callback);
}
});
Dispatcher.register(function(action) {
switch(action.actionType){
case MessageConstants.PERFORM_SEND_MESSAGE:
MessageStore.emitSubmitMessageChange();
break;
case MessageConstants.PERFORM_SEND_MESSAGE_FAIL:
MessageStore.emitSubmitMessageFailChange();
break;
default:
//noop
}
})
export default MessageStore;
And this is my action.js
.....
function _sendMessage(messageInfo, callback) {
jQuery.ajax({
method: 'POST',
url: api('supportTickets'),
contentType: 'application/json',
data: JSON.stringify(messageInfo)
})
.done(function(messageInfo) {
callback(null, messageInfo);
})
.fail(function(err){
console.error('Failed to send message : ' + JSON.stringify(err));
callback(err, null);
});
}
var MessageActions = {
sendMessage: function(messageInfo) {
_sendMessage(messageInfo, function(err, messageInfo) {
if(err) {
Dispatcher.dispatch({
actionType: MessageConstants.PERFOM_SEND_MESSAGE_FAIL
});
}
Dispatcher.dispatch({
actionType: MessageConstants.PERFORM_SEND_MESSAGE,
messageInfo
});
});
}
};
module.exports = MessageActions;
Your form should be responsible for handling errors. You should know your errors at the time of submission of the form.
handleSubmit(evt) {
evt.preventDefault();
var errorDialog;
if(this.state.subject === ''){
errorDialog = 'Error:' + T.translate('msg.subjectRequired');
} else if(this.state.description === ''){
errorDialog = 'Error:' + T.translate('msg.mailDescriptionRequired');
}
if (errorDialog) {
this.setState({
// set your error here
})
return;
}
this.handleProfileChange();
this.handleSubjectChange(evt);
this.handleMessageChange(evt);
var messageInfo = {
fullName: this.state.fullName,
site: this.state.site,
email: this.state.email,
phone: this.state.phone,
subject: this.state.subject,
description: this.state.description,
type: this.state.type
};
this.setState({ submitting: true }, () => {
MessageActions.sendMessage(messageInfo);
});
console.log(this.state.isSubmited);
}
Your component seems to be a little complex. Think about breaking your component into smaller components. Using functional components I would do this task in a way something like that.
function validateForm() {
// validate form logic here. If it's ok, returns true, otherwise, returns false
}
function Message({ form }) {
if (!validateForm(form)) {
return (
<div>Please, fill the empty fields!!</div>
)
}
return (
<div>All good. Submit the form!!</div>
)
}
I have propblems in my project
enter image description here
D:\React-Native\Expo\mobile\node_modules\expo\build\logs\RemoteConsole.js:80 Possible Unhandled Promise Rejection (id: 0):
TypeError: Cannot read property 'data' of undefined
TypeError: Cannot read property 'data' of undefined
SignUp.js
import React from 'react';
import {ScrollView, KeyboardAvoidingView, CheckBox, View, Text, Platform,} from 'react-native';
import styles from './styles/authStyles';
import ScreenTitle from '../components/ScreenTitle';
import Input from '../components/input';
import Button from '../components/Button';
import axios from '../config/axios';
import { SINGNUP_URL } from '../config/urls';
import Loader from '../components/Loader';
import Alert from '../components/Alert';
export default class SignUpScreen extends React.Component
{
constructor(props)
{
super(props);
this.state =
{
name: "",
email: "",
password: "",
specialization: "",
phone: "",
address: "",
workingHours: "",
userType: false,
location: null,
isLoading: false,
alert:
{
messages: null,
type: "",
}
}
}
componentDidUpdate()
{
if(this.state.alert.messages)
{
setTimeout(() =>
{
this.setState({alert: {messages: null}})
}, 3000)
}
}
componentWillUnMount()
{
clearTimeout();
}
changeNameHandler = (value) =>
{
this.setState({name: value})
};
changeEmailHandler = (value) =>
{
this.setState({email: value})
};
changePasswordHandler= (value) =>
{
this.setState({password: value})
};
changeSpecializationHandler = (value) =>
{
this.setState({specialization: value})
};
changePhoneHandler = (value) =>
{
this.setState({phone: value})
};
changeAddressHandler = (value) =>
{
this.setState({address: value })
};
changeWorkingHoursHandler = (value) =>
{
this.setState({workingHours: value})
};
changeUserTypeHandler = () =>
{
this.setState({ userType: !this.state.userType})
}
validate()
{
const {name, email, password, specialization, address, phone, workingHours, userType} = this.state;
let validationErrors = [];
let passed = true;
if(!name)
{
validationErrors.push(" Please put your name");
passed= false;
}
if(!email)
{
validationErrors.push(" Please put your email");
passed= false;
}
if(!password)
{
validationErrors.push(" Please put your password");
passed= false;
}
if(userType)
{
if(!specialization)
{
validationErrors.push(" Please put your specialization");
passed= false;
}
if(!address)
{
validationErrors.push(" Please put your address");
passed= false;
}
if(!phone)
{
validationErrors.push(" Please put your phone nuber");
passed= false;
}
if(!workingHours)
{
validationErrors.push(" Please put your working hours");
passed= false;
}
}
if(validationErrors.length > 0)
{
this.setState({alert: {messages: validationErrors, type: "danger"}})
}
return passed
}
_SignUp = async () =>
{
if(!this.validate()) return;
this.setState({isLoading: true})
const { name, email, password, specialization, address, phone, workingHours, userType } = this.state;
const body =
{
name,
email,
password,
specialization,
address,
phone,
workingHours,
userType: userType ? "doctor" : 'normal',
location:
{
latitude: 1,
longitude: 2
},
isLoading: false
}
try
{
const response = await axios.post(SINGNUP_URL, body);
this.setState({
name:'',
email: '',
password: '',
specialization: '',
address: '',
phone: '',
workingHours: '',
userType: false,
location: null
});
this.props.navigation.navigate("SignIn",
{
alert:{messages:"Your account has been successfully registered", type:"success"}
});
}
catch(e){
this.setState({
alert: { messages: e.response.data.message, type: "danger"},
isLoading: false
});
}
}
render()
{
const { name, email, password, specialization, address, phone, workingHours, userType, isLoading, alert } = this.state;
return(
<ScrollView contentContainerStyle={{paddingVertical: 40}}>
<Loader title="A new account is creating" loading={isLoading} />
<Alert messages={alert.messages} type={alert.type} />
<View style={styles.container}>
<ScreenTitle
title="Create new account"
icon="md-person-add"
/>
<KeyboardAvoidingView behavior="padding" enabled >
<Input
placeholder="Name"
onChangeText={this.changeNameHandler}
value={name} />
<Input
placeholder="Email"
onChangeText={this.changeEmailHandler}
value={email} />
<Input
placeholder="Password"
secureTextEntry
onChangeText={this.changePasswordHandler}
value={password} />
<View
style={styles.checkBoxContainer}
>
<CheckBox
style={styles.checkBoxLabel}
value={userType}
onChange={this.changeUserTypeHandler} />
<Text style={styles.checkBoxLabel} >Doctors</Text>
</View>
{userType && (
<React.Fragment>
<Input
onChangeText={this.changeSpecializationHandler}
placeholder="Specialization" value = {specialization} />
<Input
onChangeText={this.changeWorkingHoursHandler}
placeholder="Hours work" value={workingHours} />
<Input
onChangeText={this.changeAddressHandler}
placeholder="Address" value={address} />
<Input
onChangeText={this.changePhoneHandler}
placeholder="Phone Number" value={phone} />
</React.Fragment>
)}
<Button
text="New Account"
onPress={this._SignUp}
/>
<View style={{height: 30}} />
{/* <Button text="Home" onPress={() => this.props.navigation.navigate("Main")} /> */}
</KeyboardAvoidingView>
</View>
</ScrollView>
)
}
}
SignIn.js
import React, { Component } from 'react'
import { Text, View, KeyboardAvoidingView, AsyncStorage } from 'react-native'
import styles from './styles/authStyles';
import ScreenTitle from '../components/ScreenTitle';
import Input from '../components/input';
import Button from '../components/Button';
import axios from '../config/axios';
import { SIGNIN_URL } from '../config/urls';
import Loader from '../components/Loader';
import Alert from '../components/Alert';
import Container from '../components/Container';
import { ScrollView } from 'react-native-gesture-handler';
export default class SignIn extends Component {
constructor(props)
{
super(props);
this.state =
{
email: "",
password: "",
isLoading: false,
alert:
{
messages: null,
type: ""
}
}
}
componentDidMount()
{
const alert = this.props.navigation.getParam('alert');
if(alert)
{
this.setState({alert});
}
}
componentDidUpdate()
{
if(this.state.alert.messages)
{
setTimeout(() =>
{
this.setState({alert: {messages: null}})
}, 3000)
}
}
componentWillUnMount()
{
clearTimeout();
}
changeEmailHandler = (value) =>
{
this.setState({email: value})
};
changePasswordHandler= (value) =>
{
this.setState({password: value})
};
validate()
{
const { email, password } = this.state;
let validationErrors = [];
let passed = true;
if(!email)
{
validationErrors.push(" Please put your email");
passed= false;
}
if(!password)
{
validationErrors.push(" Please put your password");
passed= false;
}
if(validationErrors.length > 0)
{
this.setState({alert: {messages: validationErrors, type: "danger"}})
}
return passed
}
_SignIn= async () => {
if(!this.validate()) return;
this.setState({ isLoading: true });
const body = {
email: this.state.email,
password: this.state.password
};
try {
const response = await axios.post(SIGNIN_URL, body);
this.setState({ email: "", password: "", isLoading: false });
AsyncStorage.setItem("accessToken", response.data.accessToken);
} catch (e) {
this.setState({
alert: { messages: e.response.data.message, type: "danger" },
isLoading: false
});
}
}
render() {
const {email, password, isLoading, alert} = this.state;
return (
<Container>
<Alert messages={alert.messages} type={alert.type} />
<Loader title="Login" loading={isLoading} />
<ScrollView
keyboardShouldPersistTaps="handled"
contentContainerStyle={styles.container} >
<ScreenTitle title="Login" icon="md-log-in" />
<KeyboardAvoidingView behavior="padding" enabled>
<Input
onChangeText={this.changeEmailHandler}
value={email}
placeholder="Email" />
<Input
onChangeText={this.changePasswordHandler}
value={password}
secureTextEntry
placeholder="Password" />
</KeyboardAvoidingView>
<Button
text="Login"
onPress={this._SignIn}
/>
<View style={{height: 30}} />
{/* <Button text="Home" onPress={() => this.props.navigation.navigate("Main")} /> */}
</ScrollView>
</Container>
)
}
}
Try changing
catch (e) {
this.setState({
alert: { messages: e.response.data.message, type: "danger" },
isLoading: false
});
}
To
catch (e) {
let {response: {data: {message = ''} = {}} = {}} = e
this.setState({
alert: { messages: message, type: "danger" },
isLoading: false
});
}
And before even doing that please check the value of e using console.log and make sure message exist in the nested object.
Unable to figure out the issue as to why my store is not updating. My end goal is to have the "here is the store first name" and "here is the store last name" in the Component.js file display the first and last name of a data block I enter in the reducer (Joe and Smith respectively). Whenever I click the login button after entering proper credentials, the console logs "USERNAME AND PASS MATCH" which tells me that it recognizes that there is a match between what I'm supplying and what is in the data. But, it refuses to update the first_name and last_name of the store for some reason...
In my Component.js file:
import React from "react"
import { connect } from "react-redux"
import { setUsername, setPassword, handleLogin } from "../actions/userActions"
#connect((store) => {
return {
loginShow: store.loginShow,
loggedIn: store.loggedIn,
username: store.username,
password: store.password,
first_name: store.first_name,
last_name: store.last_name,
id: store.id,
invalidAttempt: store.invalidAttempt,
};
})
export default class Layout extends React.Component {
render() {
let loginView = null;
if (this.props.loginShow && this.props.invalidAttempt === false) {
loginView = (
<div className="loginBox">
<h3>Enter username and password</h3>
<input type="text" placeholder="Please enter username..."
onChange={(e) => this.props.dispatch(setUsername(e.target.value))} />
<br />
<input type="password" placeholder="Please enter password..."
onChange={(e) => this.props.dispatch(setPassword(e.target.value))} />
<p>Here is the store first name: {this.props.first_name}</p>
<p>Here is the store last name: {this.props.last_name}</p>
<br />
<button onClick={() => this.props.dispatch(handleLogin(this.props.username, this.props.password))}>Login</button>
</div>
)
}
return (
<div>
{loginView}
</div>
)
}
}
Here is the action file:
export function setUsername(name) {
return {
type: "SET_USERNAME",
payload: name,
}
}
export function setPassword(pword) {
return {
type: "SET_PASSWORD",
payload: pword,
}
}
export function handleLogin(uname, pword) {
return {
type: "HANDLE_LOGIN",
payload: {user: uname, pass: pword}
}
}
Now in my reducer file, I'm pretty sure this is where the issue is:
let data = [
{
"username": "imJoe",
"first_name": "Joe",
"last_name": "Smith",
"password": "password123",
"id": 1
}
]
export default function userReducer(state = {
loginShow: true,
loggedIn: false,
username: '',
password: '',
first_name: '',
last_name: '',
id: '',
invalidAttempt: false,
check: false,
}, action) {
switch (action.type) {
case "SET_USERNAME": {
console.log("SET USERNAME REUCER")
return { ...state, username: action.payload }
}
case "SET_PASSWORD": {
console.log("SET PASS REUCER")
return { ...state, password: action.payload }
}
case "HANDLE_LOGIN": {
console.log("HANDLE LOGIN REDUCER")
data.map(xyz => {
if (xyz.username === action.payload.user && xyz.password === action.payload.pass){
console.log("USERNAME AND PASS MATCH")
return {
...state,
first_name: xyz.first_name,
last_name: xyz.last_name,
}
}
})
}
}
return state
}
Your store not update because in your case "HANDLE LOGIN", you return nothing. From redux docs: reducer always should return new state, but you only map and return nothing.
Here is how "HANDLE_LOGIN" should look like:
case "HANDLE_LOGIN": {
console.log("HANDLE LOGIN REDUCER")
let firstName = null;
let lastName = null;
data.map(xyz => {
if (xyz.username === action.payload.user && xyz.password === action.payload.pass){
console.log("USERNAME AND PASS MATCH")
firstName = xyz.first_name;
lastName = xyz.last_name;
}
});
return {
...state,
first_name: firstName,
last_name: lastName,
}
}
So you reducer reŠµurns data, even data items is null your reducer returns items with null.