useState() hook not updating the value on change - javascript

Little context, I am trying to create a form for for getting User Signup.
I first wrote code as following .
import { useState } from 'react';
const SignupComponent = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
error: '',
loading: false,
message: '',
showForm: true
})
const { name, email, password, error, loading, showForm } = formData;
const onChange = e => {
setFormData({ ...formData, error: false, [e.target.name]: e.target.value })
console.log(name)
}
const handleSubmit = async e => {
e.preventDefault();
console.table({ name, email, password, error, loading, showForm })
}
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Enter Your Name" values={name} onChange={e => onChange(e)} />
</div>
<div className="form-group">
<input values={email} onChange={e => onChange(e)} type="email" className="form-control" placeholder="Enter Your Email" />
</div>
<div className="form-group">
<input values={password} onChange={e => onChange(e)} type="password" className="form-control" placeholder="Enter Your Password" />
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>{signupForm()}</React.Fragment>};
export default SignupComponent;
I noticed that in this code snippet, the state in setFormData is not getting updated, console logging name or any other value returns a empty string.
result for the above code
But after tweaking the code as such
import { useState } from 'react';
const SignupComponent = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
error: '',
loading: false,
message: '',
showForm: true
})
const { name, email, password, error, loading, showForm } = formData;
const handleChange = value => (e) => {
setFormData({ ...formData, error: false, [value]: e.target.value })
console.log(name)
}
const handleSubmit = async e => {
e.preventDefault();
console.table({ name, email, password, error, loading, showForm })
}
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Enter Your Name" values={name} onChange={handleChange('name')} />
</div>
<div className="form-group">
<input values={email} onChange={handleChange('email')} type="email" className="form-control" placeholder="Enter Your Email" />
</div>
<div className="form-group">
<input values={password} onChange={handleChange('password')} type="password" className="form-control" placeholder="Enter Your Password" />
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>{signupForm()}</React.Fragment> };
export default SignupComponent;
Makes the code work and result is as desired. As in this image.
2nd way
Why is this behaving like this. Why is the first way not working.

You forgot the name attribute in your inputs, and the value attribute without s
<input name="email" value={email} onChange={onChange} ... />
then
const onChange = e => {
// The event will get passed as an argument even if you don't bind it in onChange={onChange}.
console.log(e.target.name, e.target.value)
setFormData({ ...formData, error: false, [e.target.name]: e.target.value })
}
The event will get passed as an argument.
It works for the second cause you're passing the name as an argument

see docs, https://reactjs.org/docs/thinking-in-react.html
React’s one-way data flow (also called one-way binding) keeps everything modular and fast.
Important thing to solve your question.
The Functional Component(FC) state is changed, UI is re-rendered.
But, your signupForm render function is declared in FC.
So, It is re-delcared as a new, when SignupComponent state is changed.
First. change signupForm render function to FC component.
Second, Pass props to component.
Thrid, re-used them.
import React from 'react'; // React is required to render JSX
const FormInput = ({
type,
placeholder,
value,
onChange,
}) => (
<div className="form-group">
<input type={type} className="form-control" placeholder={placeholder} value={value} onChange={onChange} />
</div>
);
const SignupComponent = () => {
const [formData, setFormData] = React.useState({
name: '',
email: '',
password: '',
error: false,
loading: false,
message: '',
showForm: true,
});
const {
name, email, password, error, loading, showForm,
} = formData;
const handleChange = (value) => (e) => {
setFormData({
...formData,
error: false,
[value]: e.target.value,
});
console.log(name);
};
const handleSubmit = async (e) => {
e.preventDefault();
console.table({
name, email, password, error, loading, showForm,
});
};
return (
<form onSubmit={handleSubmit}>
<FormInput type="text" value={name} placeholder="Enter Your Name" onChange={handleChange('name')} />
<div>
<button type="submit" className="btn btn-primary">Signup</button>
</div>
</form>
);
};
export default SignupComponent;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Related

BAD_USER_INPUT Error on Edit value on form user

Problem
I'm currently working on reactjs + apollo client projects. I'm developing edit user feature. for querying user by username, it works.
but when i'm change the data information. it throws error like this.
Also , i'm getting this error.
Code
Mutation
mutation($username: String!, $input: EditUser!) {
updateUser(username: $username, input: $input) {
full_name
email
group_id
phone
address
}
}
ModalEdit.js
import React, { useEffect, useState } from "react";
import { useQuery, useMutation } from "#apollo/client";
import { Button, Modal, Form } from "react-bootstrap";
import { GET_USER_BY_ID } from "../../../gql/query";
import { UPDATE_USER } from "../../../gql/mutation";
const ModalEdit = (props) => {
// state for check input component
const [isChecked, setIsChecked] = useState("ACTIVE");
// state for input values
const [value, setValue] = useState({
group_id: "",
full_name: "",
email: "",
phone: "",
address: "",
password: "",
});
useEffect(() => {
if (props.show) {
document.body.classList.add("modal-open");
}
return () => {
if (document.body.classList.contains("modal-open")) {
document.body.classList.remove("modal-open");
}
};
}, [props.show]);
const { data, loading, error } = useQuery(GET_USER_BY_ID, {
variables: { username: props.username },
});
const [updateUser, { error: updateError, loading: updateLoading, refetch }] =
useMutation(UPDATE_USER, {
onCompleted: (data) => {
refetch();
},
onError: (err) => {
console.error(JSON.stringify(err, null, 2));
},
});
const dataUser = data?.getUserByID;
useEffect(() => {
if (dataUser) {
setValue({
group_id: dataUser.group_id,
full_name: dataUser.full_name,
email: dataUser.email,
phone: dataUser.phone,
address: dataUser.address,
password: dataUser.password,
});
}
}, [dataUser]);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
const handleChange = (event) => {
const { name, value } = event.target;
setValue({ ...value, [name]: value });
};
// handle mutation for edit user
const handleSubmit = (event) => {
event.preventDefault();
console.log(value.full_name);
updateUser({
variables: {
username: props.username,
input: {
group_id: value.group_id,
full_name: value.full_name,
email: value.email,
phone: value.phone,
address: value.address,
password: value.password,
},
},
});
};
return (
<Modal show={props.show}>
<Modal.Header>
<Modal.Title>
{" "}
<span>FORMULIR AKUN PENGGUNA</span>{" "}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3">
<Form.Label>Role Akun</Form.Label>
<Form.Select
aria-label="pilih user role"
name="group_id"
onChange={handleChange}
>
<option value={value.group_id}>{value.group_id}</option>
</Form.Select>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Nama Lengkap</Form.Label>
<Form.Control
type="text"
name="full_name"
value={value.full_name}
onChange={handleChange}
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
name="email"
value={value.email}
onChange={handleChange}
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Phone</Form.Label>
<Form.Control
type="text"
name="phone"
value={value.phone}
onChange={handleChange}
/>
</Form.Group>
<Form.Label>Aktifkan Akun</Form.Label>
{dataUser.status === "ACTIVE" ? (
<Form.Check
type="switch"
checked={isChecked}
onChange={(event) => setIsChecked(event.target.checked)}
id="custom-switch"
label="Aktifkan Akun"
/>
) : (
<Form.Check
type="switch"
id="custom-switch"
checked={isChecked}
onChange={(event) => setIsChecked(event.target.checked)}
label="Aktifkan Akun"
/>
)}
<Button variant="primary" type="submit">
Submit
</Button>
<Button variant="secondary" onClick={props.onClose}>
Close
</Button>
</Form>
</Modal.Body>
</Modal>
);
};
export default ModalEdit;
Question
How to fix BAD_USER_INPUT request?
How to check if email is controlled/uncontrolled components?
any help will be appreciated, thank you
It looks like the input type needs a full_name field as well. I think your problem lies with:
// state for input values
const [value, setValue] = useState({
group_id: "",
full_name: "",
email: "",
phone: "",
address: "",
password: "",
});
...
const handleChange = (event) => {
const { name, value } = event.target;
setValue({ ...value, [name]: value });
};
Because in the context of this function value is == event.target.value and not the value you defined in your setState:
Therefore setValue({...value, [name]: value}); will completely override the state.
Try aliasing the target's value:
const handleChange = (event) => {
const { name, value:tValue } = event.target;
setValue({ ...value, [name]: tValue });
};
I suspect this is a consequence of value.email suddenly becoming undefined based on (1).

Unable to type anything in textbox after state empty Reactjs

I am working on Reactjs/nextjs,Right now i am integrating newsletter(submit form) but once i submit form then unable to type anything in textbox,How can i fix this ? I tried with make "state" empty but still unable to type anything, Here is my current code
const [state, setState] = useState({});
const handleSubmit = (e) => {
e.preventDefault();
const data = {
name: e.target.name.value,
country: e.target.country.value,
msgs: e.target.msgs.value,
};
axios
.post("xxxxxxxxxxxxxxxxxxxxxxxx",data)
.then(function (response) {
if (response.data.msg == "exist") {
$("#msg4").show("slow").delay(5000).fadeOut();
setState({
...state,
name: ""
});
} else {
}
});
return (
<>
<form className="row" id="home_contact_form" onSubmit={handleSubmit}>
<input
type="text"
name="name"
id="name"
placeholder="Enter Your Email"
value={state.name}
// onChange={handleChange}
className="input-group"
/>
<input type="submit" value="send" className="sendbtn" id="sendbtn" />
</form>
</>
)
if you want to couse the input be a controlled component you can do
so:
const [state, setState] = useState({ name: '' });
and provide an event handler for onChange
const handleChange = (event) => setState({...state, name: event.target.value })
<input
type="text"
name="name"
id="name"
placeholder="Enter Your Email"
value={state.name}
onChange={handleChange}
className="input-group"
/>

where to call the Axios post request in reactjs

I have a form,thats data are saved in the state to be sent to the backend server.
i am handling the form with handleSubmit function and useEffect hook, where the handleSubmit prevents the form from being submitted unless it calls the validation function, in the useEffect I check if there are any errors using if condition and then console.log my data.
now I want to post the data hold in the state -the state is sent as a props to me- but I am confused whether to put the request in the HandleSubmit function or in the useEffect inside the body of the if condition.
import react, { Component, useState, useEffect } from 'react';
import {useNavigate } from 'react-router-dom';
import axios from 'axios';
import './sign.css';
const SignA = (props) => {
const navigate = useNavigate();
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleSubmit = (err) => {
err.preventDefault();
setFormErrors(validate(props.data));
setIsSubmit(true);
}
useEffect(() => {
console.log(Object.keys(formErrors).length);
if (Object.keys(formErrors).length === 0 && isSubmit) {
console.log('console the props data', props.data)
//here is where I think the post request should be put
if (isSubmit) {
return (navigate('/profileadmin'))
}
}
}, [formErrors])
const validate = (values) => {
const errors = {};
const regex = /^[^\s#]+#[^\s#]+\.[^\s#]{2,}$/i;
if (!values.firstname) {
errors.firstname = 'firstname is required!';
}
if (!values.lastname) {
errors.lastname = 'lastname is required!';
}
if (!values.mobile) {
errors.mobile = 'mobile is required!';
}
if (!values.email) {
errors.email = 'email is required!';
} else if (!regex.test(values.email)) {
errors.email = 'this is not a valid email format!'
}
return errors;
}
return (
<div className='signup'>
<form onSubmit={handleSubmit} >
<div className="container">
<h1>Sign Up</h1>
<div className="name">
<div>
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={props.change}
/>
</div>
<div>
<input
type="text"
placeholder="Last name"
name="lastname"
value={props.data.lastname}
onChange={props.change}
/>
</div>
</div>
<p className='errorMsg'>{formErrors.firstname}</p>
<p className='errorMsg'>{formErrors.lastname}</p>
<br />
<div>
<input
type="text"
placeholder="Business mobile number"
name="mobile"
value={props.data.mobile}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.mobile}</p>
<br />
<input
type="text"
placeholder="Email Adress"
name="email"
value={props.data.email}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.email}</p>
<br />
</div>
</div>
<br />
<div className="checkbox">
<label>
<input type="checkbox" className="check" />i’ve read and agree with <a href="url" >Terms of service</a>
</label>
</div>
<div className="clearfix">
<button type="submit" className="signupbtn">Sign Up</button>
</div>
</div>
</form >
</div >
)
}
export default SignA;
this is the request
axios.post('', props.data)
.then(res => console.log('post res', res))
.catch(error => {
console.error('There was an error in post request!', error);
});
You don't necessarily need useEffect here.
Here is how you can implement such thing:
Declare a state to hold form values:
const [formData, setFormData] = useState({})
Declare function to set the state:
const handleChange = (name, value) => {
setFormData({...formData, [name]: value})
}
Input onChange to capture:
// handleChange has two parameters
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={(event) => handleChange('firstName', event.target.value)}
/>
function for calling post axios post request
const handleSubmit = () => {
//check for validations code here
// if validations are right then post request here
// this will give you all the fields like firstName: "", lastName: ""
let requestBody = {
...formData
}
axios.post("url", requestBody).then((res)=> {
//your code here
})
}

Form Validation - react

index.js
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import { ToastContainer, toast } from 'react-toastify';
import { useHistory } from 'react-router-dom';
import 'react-toastify/dist/ReactToastify.css';
const AddRequest = () => {
const [request, setRequest] = useState({
product_name: '',
description: '',
product_img: '',
});
const [error, setError] = useState({
product_error: ''
})
const handleChange = e => {
e.preventDefault();
const {name, value} = e.target;
let formError = {...error};
switch(name) {
case "product_error":
formError.product_error =
value.length < 0 ? "Required" : "";
break;
default:
break;
}
setError({formError, [name]: value});
console.log(error)
setRequest({ ...request, [e.target.name]: e.target.value });
};
const headers = {
'x-access-token': localStorage.getItem('accessToken'),
'content-type': 'multipart/form-data'
}
const handleImageChange = async e => {
e.preventDefault();
setRequest({ ...request, [e.target.name]: e.target.files });
};
const handleSubmit = async e => {
e.preventDefault();
const formData = new FormData()
for (const file of request.product_img) {
formData.append('product_img', file)
}
formData.append('product_name', request.product_name)
formData.append('description', request.description)
await Axios.post(config.api, formData, {
headers: headers
})
.then(res => {
toast.success('Added Successfully!', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
.catch(e => {
console.log(e)
toast.error('not Added', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
setTimeout(function () {
history.push('/')
}, 1500);
};
return (
<>
<ToastContainer />
<form onSubmit={e => handleSubmit(e)} noValidate>
<div className="form-group">
<label htmlFor='product_name'>Product Name:</label>
<input type="text" name="product_name" id="product_name" placeholder="Enter Product Name" className="form-control" noValidate onChange={e => handleChange(e)} />
{errors.product_error}
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='description'>Description:</label>
<input type="text" name="description" id="description" placeholder="Description" className="form-control" onChange={e => handleChange(e)} />
</div>
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='product_img'>Product Image:</label> <br />
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} />
</div>
<button type="submit" className="btn btn-success"> Add Request Rekko </button>
</form>
</>
)
};
export default AddRequest
Everything is working fine but form validation is not working. I am new to react and tried many things but still, it is not working. Can anyone help me with form validation? I only want all 3 fields to be required. It shows the message that this field is required if someone submits a form without entering anything.
You can simply add the tag required inside the input, like this:
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} required />

value is not shown in the field when using redux form

I am using redux-form for the form. The form gets submitted but if page is refreshed
I need to show that submitted data which comes from the server. Everything is working,
the local state is also updated from getDerivedStateFromProps but the field does not
show with the data. I used plain input tag and it shows up the data. What have i missed?
Here is what I have done
UPDATE
const mapStateToProps = (state) => {
const { company } = state.profile.companyReducer;
return {
getCompany: state.profile.companyReducer,
initialValues: company && company.records,
};
};
const mapDispatchToProps = dispatch => ({
loadCompany: () => dispatch(loadCompany()),
saveCompany: companyData => dispatch(saveCompany(companyData)),
});
const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
const withReduxForm = reduxForm({
form: 'companyForm',
fields: requiredFields,
validate,
// initialValues: {
// company_name: 'company',
// },
destroyOnUnmount: false,
enableReinitialize: true,
keepDirtyOnReinitialize: true,
});
const initialState = {
company_name: 'hello',
website: '',
industry: '',
number_of_employees: '',
phone_number: '',
founded: '',
address: '',
city: '',
state: '',
zip_code: '',
country: '',
wiki: '',
headquarter: '',
speciality: '',
type: '',
};
const enhance = compose(
withReduxForm,
withConnect,
withState('company', 'updateCompany', initialState),
withHandlers({
handleChange: props => ({ target: { name, value } }) => {
props.updateCompany({ ...props.company, [name]: value });
},
handleSubmit: props => (event) => {
event.preventDefault();
props.saveCompany(props.company);
},
}),
setStatic('getDerivedStateFromProps', (nextProps) => {
const { company } = nextProps.getCompany;
if (company && company.records !== undefined) {
console.log('company records getDerivedStateFromProps', company.records);
return {
company: company.records,
};
}
return null;
}),
lifecycle({
componentDidMount() {
this.props.loadCompany();
},
}),
);
export default enhance;
const Company = ({
company,
handleChange,
handleSubmit,
}: {
company: Object,
handleChange: Function,
handleSubmit: Function
}) => {
console.log('company', company);
return (
<React.Fragment>
<FormHeadline headline="Company" weight="400" />
<Wrapper>
<GridContainer container spacing={24}>
<StyledForm autoComplete="off" onSubmit={handleSubmit}>
<FormWrapper>
<input
name="company_name"
id="company_name"
type="text"
label="Company Name"
className="input-field"
value={company.company_name}
onChange={handleChange}
/>
{/* <Field
id="company_name"
name="company_name"
type="text"
label="Company Name"
className="input-field"
value="Hello"
onChange={handleChange}
component={GTextField}
required
margin="normal"
/> */}
<Field
id="website"
name="website"
type="text"
label="Website"
placeholder="Website"
className="input-field"
value={company.website}
onChange={handleChange}
component={GTextField}
required
margin="normal"
/>
</FormWrapper>
</StyledForm>
</GridContainer>
</Wrapper>
</React.Fragment>
);
};
export default enhance(Company);
generic text field
const GTextField = ({
input,
label,
meta: { touched, error },
...rest
}: {
input: any,
label: Node,
meta: {
touched: boolean,
error: boolean
}
}) => {
console.log('rest', input);
return (
<TextField
label={label}
helperText={touched && error}
error={!!(touched && error)}
{...input}
{...rest}
/>
);
};
This works but not the Field one
<input
name="company_name"
id="company_name"
type="text"
label="Company Name"
className="input-field"
value={company.company_name}
onChange={handleChange}
/>
UPDATE
props.initialValues shows the following but still the field is not updated
here is the full code
https://gist.github.com/MilanRgm/e3e0592c72a70a4e35b72bb6107856bc
Hi first replace the input tag with the commented out field component itself then set these flags in reduxform
const withReduxForm = reduxForm({
form: 'companyForm',
fields: requiredFields,
validate,
destroyOnUnmount: false,
enableReinitialize: true,
keepDirtyOnReinitialize: true
});
as well as pass the initialValues props to the form container with the server response
{
company_name: 'response value from server'
}
Hi checkout this fiddle link for initialValues example. For your example with reducer
const mapStateToProps = state => ({
getCompany: state.profile.companyReducer,
initialValues: state.profile.[your reducer object] });

Categories

Resources