Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested React <input> element loses focus on typing

Tags:

reactjs

I have:

  • A component App with a child component Filter.
  • The child needs to mutate state in the parent, which it is doing via an <input onChange={handler}>.
  • The handler is a prop that is set on the child by the parent.

All good so far.

However, whenever the a key is pressed on the input, it loses focus. I presume it's being destroyed and re-rendered.

If I hoist the Filter component up a level into the App and drive it off the state in that, then everything works as you'd expect, but obviously I'd like to be able to nest the components and share the state at the top level.

I guess calling setState at this higher level is causing the whole thing to get re-rendered, but I thought the diffing algorithm would be clever enough to avoid replacing the node in the Filter sub-component and thus avoid blurring the focus on the <input>.

What am I doing wrong / how can I fix this? Is there a better way to structure this?

Working JSBin here: http://jsbin.com/fexoyoqi/10/edit?html,js,output

var App = React.createClass({
  getInitialState: function() {
    return {
      items: ["Tom", "Dick", "Harry"],
      filterText: ''
    };
  },

  setFilterText: function (event) {
    this.setState({filterText: event.target.value});
  },

  render: function () {
    var filter = React.createClass({
      render: function () {
        return <input value={this.props.filterText} onChange={this.props.onChange}/>;
      }
    });

    var rows = this.state.items
      .filter(function (item) {
        return this.state.filterText == ''
          ? true
          : item.toLowerCase().indexOf(
              this.state.filterText.toLowerCase()) > -1;
      }.bind(this))
      .map(function(item) {
        return <li>{item}</li>
      });

    return (
      <div>
        Filter: <filter filterText={this.state.filterText}
          onChange={this.setFilterText}/>
        <ul>
          {rows}
        </ul>
      </div>
    );
  }
});

React.renderComponent(<App />, document.body);
like image 442
Alastair Maw Avatar asked Aug 19 '14 14:08

Alastair Maw


People also ask

Why does the input field lose focus after typing a character React?

it is because you are rendering the form in a function inside render(). Every time your state/prop change, the function returns a new form. it caused you to lose focus.

How do I stop Rerendering in React?

1. Memoization using useMemo() and UseCallback() Hooks. Memoization enables your code to re-render components only if there's a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.

How do you move focus on next field when Enter is pressed in React?

We can use focus() function to focus the particular input field.


1 Answers

You're creating a new component class inside the render function.

Part of react's diffing algorithm looks at the components, and if it sees you rendered a different type component in one spot it says "the structure is probably significantly different, so I won't waste time diffing the children". It throws out the node, and renders the new result to the DOM.

Move var filter = React.createClass... somewhere it's only executed once, and it'll work fine.

like image 179
Brigand Avatar answered Oct 05 '22 11:10

Brigand