(p)React avoid unnecessary rerender on submit
Asked Answered
E

2

8

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>
Ectosarc answered 8/9, 2019 at 15:3 Comment(1)
You don't have focus from the beginning either. You need to use refs to do that.Halm
C
1

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.

Chessboard answered 14/9, 2019 at 11:32 Comment(2)
got it, the same tags makes React mess what to update and what to create.Chessboard
Correct, it is the reconciliation algorithm. Another fix is moving the error div below the inputEctosarc
S
0

You cannot avoid rerender because on setting state or props changes will component renders again. You focus the element again by using ref. Updated your sample code.

Demo Link

Saks answered 8/9, 2019 at 15:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.