How to combine useState and useEffect properly - javascript

I want to compare 2 inputs value. The typical password/repeat password input in a form.
Using onChange react useState render the DOM but not immediately because I shopuld use useEffect.
But I'm not sure how to combine both. I'm conscious there is other answers replying something similar but I can't apply to this case.
This is my useSstate:
const [user, setUser] = useState({
username: '',
password: '',
});
This is my onInputChange function:
const onInputChange = (e) => {
if ((e.target.id === 'password') === (e.target.id === 'confirmPassword')) {
console.log('Match!')
} else {
console.log('DO NOT Match')
}
setUser({ ...user, [e.target.name]: e.target.value });
console.log('User Updating values: ', user)
}
This is the input (MUI textfield):
<TextField
id="password"
name="password"
label="Password"
type="password"
onChange={(e) => onInputChange(e)}
/>
<TextField
id="confirmPassword"
name="confirmPassword"
label="Confirm password"
type="password"
onChange={(e) => onInputChange(e)}
/>
Could you help me with this, please?

Here you can find how it works
CodeSandBox
This is not best practice because you should match password on submit or on blur event trigger on each input.
Ask me if you need furthur help !
Thank You.

Related

An Elegant Way to add Confrim Password field in React

I have a project in which I have to add a registration form and I want to to validate that the password and confirm fields are equal without clicking the register button.
If password and confirm password field will not match, then I also want to put an error message at side of confirm password field and disable registration button.
I had these for handle password and username
const LoginForm = ({ register = false }) => {
const [isLoading, setLoading] = React.useState(false)
const [errors, setErrors] = React.useState([])
const [username, setUsername] = React.useState('')
const [email, setEmail] = React.useState('')
const [password, setPassword] = React.useState('')
const handleUsernameChange = React.useCallback(
(e) => setUsername(e.target.value),
[setUsername]
)
const handleEmailChange = React.useCallback(
(e) => setEmail(e.target.value),
[]
)
const handlePasswordChange = React.useCallback(
(e) => setPassword(e.target.value),
[]
)
and Got handle submit
const handleSubmit = async (e) => {
e.preventDefault()
setLoading(true)
try {
let data, status
if (register) {
;({ data, status } = await UserAPI.register(username, email, password))
} else {
;({ data, status } = await UserAPI.login(email, password))
}
if (status !== 200 && data?.errors) {
setErrors(data.errors)
}
if (data?.user) {
// We fetch from /profiles/:username again because the return from /users/login above
// does not contain the image placeholder.
const { data: profileData, status: profileStatus } = await UserAPI.get(
data.user.username
)
if (profileStatus !== 200) {
setErrors(profileData.errors)
}
data.user.effectiveImage = profileData.profile.image
window.localStorage.setItem('user', JSON.stringify(data.user))
setCookie('auth', data.user.token)
mutate('user', data.user)
Router.push('/')
}
} catch (error) {
console.error(error)
} finally {
setLoading(false)
}
}
I want to add new confirm password field to this
<form onSubmit={handleSubmit}>
<fieldset>
{register && (
<fieldset className="form-group">
<input
className="form-control form-control-lg"
type="text"
placeholder="Username"
value={username}
onChange={handleUsernameChange}
/>
</fieldset>
)}
<fieldset className="form-group">
<input
className="form-control form-control-lg"
type="email"
placeholder="Email"
value={email}
onChange={handleEmailChange}
/>
</fieldset>
<fieldset className="form-group">
<input
className="form-control form-control-lg"
type="password"
placeholder="Password"
value={password}
onChange={handlePasswordChange}
/>
</fieldset>
<button
className="btn btn-lg btn-primary pull-xs-right"
type="submit"
disabled={isLoading}
>
{`${register ? 'Sign up' : 'Sign in'}`}
</button>
</fieldset>
</form>
What is the most elegant way to add confirm password validation?
The elegant way to create a form, in general, is using a form library. The form libraries will make your work easier, more elegant, and more developable. Most of them have a technique to use a function or a scheme as a validator that will help you certify your password.
The most popular form libraries currently are Formik and React Hook Form and if you are using Redux you can use Redux Form.
In case you want to continue your current way of handling the form the best possible name for the second field is passowrdConfirmation is the best name in my Idea. Furthermore, you can create a validation function that you process before every field change(using a useEffect hook) or before submitting(using onSubmit event on form element).
You can use "useEffect" hook to listen to password and confirm password inputs.
Here is a simple example: https://codesandbox.io/s/solitary-brook-tw15c

Yup and react hook form input validation bug

I have a problem in the input validation. The validation works when I submit and a error message appears, but when I press the first key on the keyboard nothing appears in the textarea and the error message disappears; after that, I can write normally. Its an inconvenience and I don't know why its happening. I am using the TextArea from Material UI. The code snippet of a login form is below.
const schema = yup.object().shape({
username: yup.string().matches(/^[a-z0-9]+$/, 'Must be all lower-case letters.').required(),
password: yup.string().required(),
})
const Login = props => {
const [formValues, setFormValues] = React.useState({
username: "",
password: ""
});
const { register,errors, handleSubmit } = useForm({
resolver: yupResolver(schema),
mode: 'onSubmit',
});
const onSubmit = async (data, e) => {
e.preventDefault()
const isValid = await schema.isValid(data)
if(isValid){
console.log(data);
}
}
return (
<Container component="main" maxWidth="xs">
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<TextField
autoFocus
required
fullWidth
id="username"
label="Username"
name="username"
value={formValues.username}
inputRef={register}
helperText = {errors.username?.message}
/>
<TextField
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
value={formValues.password}
inputRef={register}
helperText = {errors.password?.message}
/>
<Button
type="submit"
fullWidth
className={classes.submit}
>
Login
</Button>
</form>
</div>
</Container>
);
}
I worked around this (in React Native) by using reValidateMode:"onBlur" in the useForm() options.
This way it doesn't retry the validation until the user leaves the input.

input lose focus on setState React

Whenever I am using setState my focus of input lost.
Where I am going wrong please tell me.
I am new to React.
This is my child component here I am using material-ui:-
const { onChangeEmail, onChangePassword, onPressSignIn, emailValue, passwordValue } = props;
<TextField
onChange={onChangeEmail}
value={emailValue}
variant="outlined"
id="email"
label="Enter your email"
name="email"
autoComplete="email"
/>
<TextField
onChange={onChangePassword}
value={passwordValue}
variant="outlined"
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
my Parent component:-
const [state, setState] = useState({
email: "",
password: "",
})
<SigninForm
onChangeEmail={(evt) => {
setState({
...state,
email : evt.target.value
})
}}
emailValue={state.email}
passwordValue={state.password}
onChangePassword={(evt) => {
setState({
...state,
password : evt.target.value
})
}}
/>
Thanks!!!
Your useState hook triggers render SigninForm each time you type as a result you loose focus. You can try onBlur to update state on focus out event and don't pass values to input

HandleChange/setState stopped working after migrating to react useState hook

I had a component using classBased react, and it was working fine, I decided to switch to usestate and it stopepd working. Now the handlechange records the state in a random manner, but it doesnt work properly
My handlechange and the useState
const [state, setState] = useState({
email: "",
password: "",
wrongCombo: false,
serverError: false
})
const handleChange = (evt) => {
const target = evt.target;
const value = target.value;
const name = target.name;
console.log(name)
console.log(value)
setState({
[name]: value
});
}
My handlesubmit (it detects random values in that console.log, icant find the logic, but the log wont get both values as per inputed in the handlechange)
const handleSubmit = (event) => {
event.preventDefault();
const { email, password } = state;
console.log(state)
props.login(email, password, "login").
then(data => {
}).catch((err) => {
if (err == "Error: Request failed with status code 403") {
setState({
wrongCombo: true
}, () => {
})
} else if (err == "Network error") {
setState({
serverError: true
})
}
})
}
And this is my render
<div>
<form>
{state.wrongCombo ? <Alert variant="danger" dismissible onClose={handleDismiss}> Wrong email and password combination </Alert> : null}
{state.serverError ? <Alert variant="danger" dismissible onClose={handleDismiss}> Server Error </Alert> : null}
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" name="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email" onChange={handleChange} />
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="Password" onChange={handleChange} />
</div>
<div className="text-center buttonContainer">
<button type="submit" class="btn btn-primary buttonLogin" onClick={handleSubmit}>Submit</button>
</div>
</form>
</div>
From the docs on useState:
unlike this.setState in a class, updating a state variable always replaces it instead of merging it.
You must replace all values in a useState object when updating them. You are only providing an object to the updater with one of the keys, so only that key will be retained.
A simple pattern for doing this would be to spread the previous state before passing your update:
setState(prev => ({...prev, [newKey]: newVal }));

React hooks not updating state properly with dynamic naming

I have a react component, which is used to make a login request to my server.
It is inside a modal, where I'm using Material UI
<TextField
onChange={handleChange}
autoFocus
name="email"
margin="dense"
id="email"
label="Email Address"
type="email"
fullWidth
/>
<TextField
onChange={handleChange}
autoFocus
name="password"
margin="dense"
id="password"
label="Password"
type="password"
fullWidth
/>
Then i have this state along with a handler to set the state properly.
const [state, setState] = React.useState({
email: '',
password: '',
valid: false
})
const handleChange = (event) =>{
event.preventDefault()
console
setState((state) => ({[event.target.name]: event.target.value, ...state}))
if(state.email.length !== 0 && state.password.length !== 0){
setState((state) => ({valid: true, ...state}))
}
}
However when ever the function is called, i con log out the syntheticEvent and get the correct values, but nothing is being set, when i log out the state afterwards. I have little experience in working with complete state objects, with hooks, so i can't really figure out the issue.
The name property is null, after the function is called three times and i get this warning
This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property `target` on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist().
As the warning suggests, try updating the state once:
const handleChange = event => {
event.preventDefault();
const { name, value } = event.target;
setState(state => {
const { email, password } = state;
const valid = email.length !== 0 && password.length !== 0;
return { [name]: value, valid, ...state };
});
};

Categories