Reputation: 83
Here is a small extract from a contact form I am making in a personal project.
In this condition the handleInputChange()
on the email input works as expected (I can free-type in the field and the field updates dynamically).
const FeedbackForm = () => {
let [formValues, setFormValues] = useState({ email: "" });
const handleInputChange = (target) => {
const updatedFormValues = {
...formValues,
[target.name]: target.value,
};
setFormValues(updatedFormValues);
};
const handleSubmit = (e) => {
e.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<input
name="email"
value={formValues.email}
onChange={(e) => handleInputChange(e.target)}
/>
<button type="submit">Submit</button>
</form>
);
};
Later in the development I decided I wanted to conditionally show/hide the email field so I abstracted it out to a separate component with a boolean prop to toggle the visibility of the element.
const FeedbackForm = ({
emailFormFieldEnabled,
}) => {
let [formValues, setFormValues] = useState({ email: "" });
const handleInputChange = (target) => {
const updatedFormValues = {
...formValues,
[target.name]: target.value,
};
setFormValues(updatedFormValues);
};
const handleSubmit = (e) => {
e.preventDefault();
};
const EmailFormField = ({ visible }) => {
if (!visible) {
return null;
}
return (
<input
name="email"
value={formValues.email}
onChange={(e) => handleInputChange(e.target)}
/>
);
};
return (
<form onSubmit={handleSubmit}>
<EmailFormField visible={emailFormFieldEnabled} />
<button type="submit">
Submit
</button>
</form>
);
};
The toggling visibility works but this appears to have broken the handleInputChange()
function. I can no longer free type in the input. I can select the input and type a single character but no more. If I want to type multiple characters in the field (like an email address, for example) I have to re-select the field to enter each character.
Any idea what I might be doing wrong?
Upvotes: 1
Views: 770
Reputation: 203466
You have declared the EmailFormField
component inside another component, so it's redeclared each render cycle. In other words, you are mounting a new instance each render cycle. Remounting the EmailFormField
loses any focus the previous "instance" had.
Declare EmailFormField
outside the component and pass all the value
and onChange
props in.
Example:
const EmailFormField = ({ visible, value, onChange }) => {
if (!visible) {
return null;
}
return <input name="email" value={value} onChange={onChange} />;
};
const FeedbackForm = ({ emailFormFieldEnabled }) => {
let [formValues, setFormValues] = useState({ email: "" });
const handleInputChange = (e) => {
const updatedFormValues = {
...formValues,
[e.target.name]: e.target.value
};
setFormValues(updatedFormValues);
};
const handleSubmit = (e) => {
e.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<EmailFormField
onChange={handleInputChange}
visible={emailFormFieldEnabled}
value={formValues.email}
/>
<button type="submit">Submit</button>
</form>
);
};
Upvotes: 1