donquixote1984
donquixote1984

Reputation: 63

React delegate normal event handler to document, how about a binded function?

As you know, React automatically delegate all event to the document, just like a big list here:

handleTodo(){}
render() { todos.map((todo)=><li onClick={this.handleTodo}>{todo.name}</li>)}

will generate a to do list, but the onClick event will be delegate to document, right?

BUT, the question is about the binded function.

handleTodo(todo){/**update todo */}
render(){todos.map((todo)=><li onClick={this.handleTodo.bind(this,todo)}>{todo.name}</li>)}

for each todo, there is a different binded function because of the different parameters. when does these function be generated? does React delegate these function to the document as well? what if a huge list, is there thousands of binded function cause the performance issue ?

Upvotes: 4

Views: 496

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074595

when does these function be generated?

This is going to sound a bit facetious, but: When your render function is called. And a new bound function is created for each of those, every time render is called.

(React also does some binding when the event actually occurs.)

does React delegate these function to the document as well?

More accurately, React uses a single click handler at the document level and then dispatches the event itself. It doesn't register a bunch of click handlers on document, one for each of your onClicks.

what if a huge list, is there thousands of binded function cause the performance issue ?

That's kind of a "how long is a piece of string?" question, but note this from the React events documentation:

We generally recommend binding in the constructor or using the property initializer syntax, to avoid this sort of performance problem.

Of course, if you're binding each todo item, you can't readily do that in the constructor. Perhaps you want to do it once when creating the todo and have the todo carry its handler with it.


To find out when binding occurs, we can wrap Function.prototype.bind with our own function and see it happen:

// Wrap `bind` so we can see when it's used
if (function foo() {}.name !== "foo") {
  console.log("Note: Your browser's JavaScript engine doesn't support the Function#name property");
}
const bind = Function.prototype.bind;
Function.prototype.bind = function(...args) {
  const name = this.name || "(no name)";
  console.log(`Binding "${name}"`);
  return bind.apply(this, args);
};

class Example extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = {items: [1, 2, 3, 4]};
  }
  handler(n) {
    console.log("Clicked, n = " + n);
  }
  render() {
    console.log("Entering render");
    const result =
      <div>
      {this.state.items.map(n => <div key={n} onClick={this.handler.bind(this, n)}>Click me</div>)}
      </div>
    ;
    console.log("Leaving render");
    return result;
  }
}

ReactDOM.render(
  <Example />,
  document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>

Upvotes: 4

Related Questions