When focused in the input box, hitting enter submits the form. On submit, an error causes an error to be inserted into the state which causes a rerender and creates a new element to show the error.
{error && <div>{error}</div>}
This rerenders the entire component which is unnecessary.
Surely (p)react should be able to detect that only the new error element be inserted and the rest of the DOM can remain untouched?
A consequence of this is that I lose focus of the input but also that a stripe iframe is remounted. How can I prevent this
DEMO
export default class App extends Component {
state = { val: "Sample input", error: null };
onSubmit = e => {
e.preventDefault();
this.setState({ error: "Some error" });
};
render(props, { val, error }) {
return (
<div>
<h1>Example</h1>
<form onSubmit={this.onSubmit}>
{error && <div>{error}</div>}
<div class="list">
<input
value={val}
onChange={e => this.setState({ val: e.target.value })}
/>
<button type="submit">Submit</button>
</div>
</form>
</div>
);
}
}
⭐️ Update
The issue is how react reconciles children.
Solution 1 I can avoid rerendering the entire component and maintain focus by adding the key
attribute to the conditional component.
{error && <div key='formError'>{error}</div>}
Solution 2 Alternatively I could move the conditional error below the input
<div class="list">
<input
value={val}
onChange={e => this.setState({ val: e.target.value })}
/>
<button type="submit">Submit</button>
</div>
{error && <div>{error}</div>}
Solution 3 Or use a class to hide the error
<div className={error ? 'error' : 'hide'}>{error}</div>