Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(p)React avoid unnecessary rerender on submit

Tags:

reactjs

preact

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>
like image 555
david_adler Avatar asked Sep 08 '19 15:09

david_adler


1 Answers

Initially you have <div> with input inside. After submitting form component will need to display two <div>: one for error and one for form. But what to update and what to create? Without key and having two elements of exact constructor React decides to update existing with error message(and removing form away) and to create new one where form will be rendered.

And at this move it loses focus inside field. So it's not because of re-render in general but because of reconciliation specifically.

So yes, nice catch, key solves that by suggesting React not to mess within divs but create new for error message. If you had different elements(say, div and... ul) you will never experience that. But providing key also legit way to handle that. Maybe slightly confusing from first glance.

like image 131
skyboyer Avatar answered Oct 19 '22 18:10

skyboyer