React hooks not updating state properly with dynamic naming - javascript

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 };
});
};

Related

How to combine useState and useEffect properly

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.

Problem in React typing text in a field text

This is how I have the code to save the changes
const handleChange = (e) => {
let { Nombre, value } = e.target;
setState({ ...state, [Nombre]: value });
};
And in the text field I have this: The problem here is when put the field "Value", when I give the value="Nombre" it makes it impossible to write in the text field.
<Form.Group>
<Form.Label style={{textAlign:"left"}}>Nombre</Form.Label>
<Form.Control
type="text"
placeholder="Nombre"
name="Nombre"
value="Nombre"
onChange={handleChange}
/>
</Form.Group>
Issue
The issue is that you are not destructuring the correct event property to update state.
Solution
Destructure the name and value event properties. You'll also want to be in the habit of using functional state updates to update the state and avoid issues related to stale state enclosures.
Example:
const handleChange = (e) => {
const { name, value} = e.target;
setState(state => ({
...state,
[name]: value
}));
};

my onChange event is not working on input elements

I have a component called Resume.js in which I define a function called handleChange which takes in an input paramater and based on that input value it changes my global state.
Resume.js:
import React from 'react'
import PersonalInfo from './PersonalInfo'
import { useState } from 'react'
const Resume = () => {
const [resumeStates, setResumeStates] = useState({
step: 1,
firstName: '',
lastName: '',
email: '',
phone: '',
address: '',
linkedIn: '',
jobTitle: '',
city: '',
employer: '',
startDate:'',
endDate: '',
responsibilities: ''
})
const nextStep = () => {
const {step} = resumeStates
setResumeStates({
step: step+1
})
}
const prevStep = () => {
const {step} = resumeStates
setResumeStates({
step: step-1
})
}
const handleChange = input => e => {
setResumeStates({[input]: e.target.value})
}
I am passing this handleChange function as props to a component called PersonalInfo.js as such:
return (
<PersonalInfo nextStep={nextStep} handleChange={handleChange} values={values}/>
)
In PersonalInfo.js I am using that prop as an onChange for my input fields:
import React from 'react'
const PersonalInfo = ({nextStep, handleChange, values}) => {
const continue_step = (e) => {
e.preventDefault()
nextStep()
}
return (
<div>
<div className="container-lg w-50 rounded p-3 mt-5 ">
<h2 className="mb-3">Personal Details</h2>
<form>
<div className="mb-3 row">
<div className="form-group">
<label htmlFor="fname" className="form-label">First Name:</label>
<input type="text" className="form-control" id="fname" value={values.firstName} onChange={() => handleChange('firstName')}/>
<div className={`text-danger fw-bold ${alert ? 'hidden': ''}`}>This is a required field</div>
</div>
</div>
<div className="mb-3 row">
<div className="form-group">
<label htmlFor="lname" className="form-label">Last Name:</label>
<input type="text" className="form-control" id="lname" value={values.lastName} onChange={() => handleChange('lastName')}/>
<div className={`text-danger fw-bold ${alert ? 'hidden': ''}`}>This is a required field</div>
</div>
</div>
But my onChange for my input fields is not working as I cannot type anything in my input as a results my states do not change.
I would appreciate any kind of help...
Thank you for your time and attention.
You're passing something called values to the component for the input values, but I don't see it defined anywhere. It looks like it the values should just be the state object, so pass that:
<PersonalInfo nextStep={nextStep} handleChange={handleChange} values={resumeStates}/>
^-- here --^
Additionally, you're removing all of your state values any time you set one:
setResumeStates({[input]: e.target.value})
Unlike the setState operation in older class-based components, the set operation in the useState hook does not determine the difference for you and only update the new parts. It replaces the state with the new state entirely. Make sure you keep the existing state when updating it:
setResumeStates({ ...resumeStates, [input]: e.target.value })
The same will need to be done for your other state updates as well.
And finally, you're not passing the actual change event to the change handler. Only the title. You can pass the change event to the function returned by the function of the change handler:
onChange={e => handleChange('firstName')(e)}
Or [potentially] more simply:
onChange={handleChange('firstName')}
This might be getting a little confusing though and is likely to result in bugs. (After all, it already has.) Instead of the function within a function, just accept both arguments in the handleChange function:
const handleChange = (input, e) => {
setResumeStates({...resumeStates, [input]: e.target.value})
}
And pass them both:
onChange={e => handleChange('firstName', e)}
As an aside, to help you with design-time validation of what's being passed to what functions, you might try making use of TypeScript in your React development.
Ok, you're doing a funception here.
const handleChange = input => e => {
setResumeStates({[input]: e.target.value})
}
This is a "function" that returns a "function that updates state". What you need is to bind a "function that updates state" to "onChange"
So you can try one of these.
First way, just declare a function that receive input event normally.
const handleChange = e => {
setResumeStates({[e.target.name]: e.target.value})
}
<input
type="text"
name="firstName"
value={values.firstName}
onChange={handleChange}
/>
or if you are feeling func-ky and wanna do func-ception. You can bind onChange with handleChange('firstName').
Note that "handleChange('firstName')" will return a function that accept "e" as parameter.
const handleChange = input => e => {
setResumeStates({[input]: e.target.value})
}
<input
type="text"
value={values.firstName}
onChange={handleChange('firstName')}
/>

React TypeError: Cannot read properties of undefined (reading 'name')

I am using React with Material UI's Textfield components. Was trying to find out the best way to set the form states with the least redundancy. Like for example, I have 8 different input fields. Instead of having a seperate handler for each input, like for example handleFirstName, handleLastName, handleEmail, handleInfo, etc.
So to accomplish this, I tried to create a handleChange handler which looks like below:
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
And on each component,
<TextField
className={classes.formInput}
name="firstName"
onChange={e => this.handleChange(e.target.value)}
required
id=""
type="text"
InputLabelProps={{
shrink: true,
}}
error={!firstName}
helperText="Name is required"
label="First Name"
variant="standard" />
<TextField
className={classes.formInput}
name="lastName"
onChange={e => this.handleChange(e.target.value)}
required
id=""
type="text"
InputLabelProps={{
shrink: true,
}}
label="Last Name"
variant="standard" />
And here is my state object
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
...,
};
}
These are just two of the input fields, but there are about 6 more fields that look the same. Any idea to combat this undefined name?
The problem is that you are not passing the complete event object. You are passing only the value. That is the reason why you are getting the name as undefined.
Try changing the onChange event to below -
onChange={this.handleChange}
This way you will get the complete event object in the function's e variable.
I think you need to handle multiple input field changes in single function.It is doable. try this
handleChange = (e)=>{
{name,value} = e.target;
this.setState({
[name]=value;
});
}
finally when to pass the onChange method to fields use :
onChange = {this.handleChange}

TypeError: Cannot read property 'name' of null when pressing any key react reactjs javascript redux

I am new to react and trying to show update values of an input field. When I press any key, it throws the TypeError: Cannot read property 'name' of null error.
onChange = (e) => {
e.preventDefault();
this.setState((prevState) => ({
profile: {
...prevState.profile,
[e.target.name]: e.target.value, //this is where the error is pointed
},
}));
this is my state and I am setting my state in componentDidUpdate after getting my values from the redux store.
state:
state = {
title: "Create Your Profile",
profile: {},
errors: {},
toggleSocialProfileInput: false,
};
componentDidUpdate:
componentDidUpdate(prevProps) {
if (this.props.errors !== prevProps.errors)
this.setState({ errors: this.props.errors });
if (this.props.profileReducer !== prevProps.profileReducer)
this.setState({ profile: data, title: "Edit Your Profile" });
}
I am using these as input where I am setting my values using profile state
const { profile } = this.state;
<TextField
placeholder="* Profile Handle"
name="handle"
value={profile.handle}
onChange={this.onChange}
error={errors.handle}
info="A unique handle for your profile URL. Your full name, company name, nickname"
/>
<TextField
placeholder="Status"
name="status"
value={profile.status ? profile.status : ""}
onChange={this.onChange}
error={errors.status}
info="What are you upto? Or some quote"
/>
<TextField
placeholder="Location"
name="location"
value={profile.location ? profile.location : ""}
onChange={this.onChange}
error={errors.location}
info="City or City, State (eg. Toronto, ON)"
/>
And if you want to see my TextField component:
const TextField = ({
name,
placeholder,
error,
info,
type,
icon,
disabled,
value,
onChange,
}) => {
const containerClass = icon ? "input-group mb-3" : "form-group";
return (
<div className={containerClass}>
{icon && (
<div className="input-group-prepend">
<span className="input-group-text">
<i className={icon} />
</span>
</div>
)}
<input
type={type}
className={`form-control form-control-lg ${error && "is-invalid"}`}
placeholder={placeholder}
name={name}
value={value}
onChange={onChange}
disabled={disabled}
/>
{info && <small className="form-text text-muted">{info}</small>}
{error && <div className="invalid-feedback">{error}</div>}
</div>
);
};
One way I know is that instead of profile I can declare the names of the textfields in the state but I want to keep the code short and thus want to use the profile object in state.
You are setting state using a callback. So first define e.target in a variable, then use it in your setState callback.
This should work
onChange = (e) => {
e.preventDefault();
const target = e.target;
this.setState((prevState) => ({
profile: {
...prevState.profile,
[target.name]: target.value,
},
}));
With event pooling,
The SyntheticEvent is pooled. This means that the SyntheticEvent object will be reused and all properties will be nullified after the event callback has been invoked. This is for performance reasons. As such, you cannot access the event in an asynchronous way.

Categories