I'm trying to practice React forms, and I can't seem to solve this error. I've developed a multi-input form and I need the value to update the parent's state. When I start typing in the input field it triggers the Switch case default. I'm not sure if maybe I'm typing the 'handleChange' function wrong or if I should have a separate state for the state.data. Any advice would be much appreciated
import React, { useState } from 'react';
import Form from './Form';
import Results from './Results';
function App() {
const [state, setState] = useState({
data: 1,
Name: '',
Email: '',
City: ''
});
const nextStep = () => {
setState({
data: state.data + 1
});
};
const handleChange = e => {
let field = e.target.name;
let val = e.target.value;
setState({ [field]: val });
};
switch (state.data) {
case 1:
return (
<div className='App-container'>
<Form
button='Next'
nextStep={nextStep}
name='Name'
state={state.name}
handleChange={handleChange}
/>
</div>
);
case 2:
return (
<div className='App-container'>
<Form
button='Next'
nextStep={nextStep}
name='Email'
state={state.email}
handleChange={handleChange}
/>
</div>
);
case 3:
return (
<div className='App-container'>
<Form
button='Submit'
nextStep={nextStep}
name='City'
state={state.city}
handleChange={handleChange}
/>
</div>
);
case 4:
return (
<div className='App-container'>
<Results data={state} />
</div>
);
default:
return 'Error';
}
}
export default App;
import React from 'react';
const Form = ({ button, nextStep, name, state, handleChange }) => {
const handleSubmit = e => {
e.preventDefault();
nextStep();
};
return (
<div className='Form-container'>
<form onSubmit={handleSubmit}>
<input
type='text'
placeholder={name}
name={name}
value={state}
onChange={handleChange}
/>
<input type='submit' value={button} />
</form>
</div>
);
};
export default Form;
import React from 'react';
const Results = ({ data }) => {
return (
<div>
<h1>Info</h1>
<p>{data.name}</p>
<p>{data.email}</p>
<p>{data.city}</p>
</div>
);
};
export default Results;
You losing state on handleChange
while expecting it to merge with the current one, but it is not how useState
works in contradiction to this.setState
in class components:
// Results new state: { data };
setState({ data: state.data + 1 });
// Instead update the copy of the state.
// Results new state: { data, Name, Email, City }
setState({ ...state, data: state.data + 1 });
Check useState
note in docs :
Note
Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax.
Another option is useReducer, which is more suited for managing state objects that contain multiple sub-values.
I recommend using a custom hook for form inputs.like follows
//useForm.js
const useForm = defaultValues => {
const [values, setValues] = useState(defaultValues);
const handleChange = ({ name, value }) => {
setValues(prevState => ({ ...values, [name]: value }));
};
const reset = () => {
setValues(null);
};
return [values, handleChange, reset];
};
inside component
const [formValues, handleChange, resetForm] = useForm();
return (
<>
<Input
value={formValues.name}
onChange: str => handleChange({ name: "name", value: str })
/>
<Input
value={formValues.email}
onChange: str => handleChange({ name: "email", value: str })
/>
</>
)
You need to spared old state
const handleChange = e => {
let field = e.target.name;
let val = e.target.value;
setState({ ...state, [field]: val });
};
this is setState({ ...state, [field]: val });
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.