Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requiring event listeners to be functions for binding #355

Closed
wants to merge 1 commit into from

Conversation

toddself
Copy link

Fixes #354.

This ensures that passed in listeners are functions so that they can be called correctly.

Throws if not. (matches the pattern Ember, Backbone and (I believe) Angular set forth).

Working on the CLA process via e-mail with Pete Hunt (pete@instagram.com) as mentioned in the #reactjs chat.

bankForRegistrationName[id] = listener;
} else {
throw new Error('Trying to bind an event handler to a non-function '+registrationName);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch (and I love that you wrote tests)!

We have a function called invariant, so just require that at the top var invariant = require('invariant'); and then use it here. It'll throw errors for you.

Then let's just use typeof here and put it first thing in the function.
invariant(typeof listener === 'function', 'error message here %s', registrationName);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh hey i just saw this. let me make these changes

@sophiebits
Copy link
Collaborator

I think this change is a little weird as you may want to bind a handler conditionally on some flag, so it's nice if null, etc. act as no handler:

<button onClick={!disabled && this.handleClick} />

What do you think?

@andreypopp
Copy link
Contributor

@spicyj agreed, I use this quite often

@petehunt
Copy link
Contributor

What if we checked for truthiness first? I know this doesn't fix the undefined use case, but it fixes an error if you try to add a random object as an event listener, right?

@sophiebits
Copy link
Collaborator

Yeah, we do that in ReactUpdates:

  invariant(
    !callback || typeof callback === "function",
    'enqueueUpdate(...): You called `setProps`, `replaceProps`, ' +
    '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
    'isn\'t callable.'
  );

@toddself
Copy link
Author

@zpao Yes -- sorry I misse dthat.

@spicyj & @andreypopp -- there are several ways to rectify that.

  1. Could you do:

!disabled ? onClick={this.handleClick} : false

  1. Or you could generate a noop method:

<button onClick={disabled ? this.noop : this.handleClick} />

  1. Or, if depending on how you're delegating events you could handle the noop case in your event handler:
handleClick: function(event){
   if(this.disabled) return

I feel like giving appropriate feedback rather than failing silently is always a preferable case, especially when other UI-event-binding libraries all follow the throw an error if the handler isn't a function (either at bind-time or run-time).

@toddself
Copy link
Author

@petehunt checking for truthiness first would go along way, but it would be really nice at run-time if a handler was bound to an event and it didn't exist to provide an appropriate error to the user.

Do you think that might be more appropriate? Let you do what you want at bind-time, but when it comes to fire the event if the handler isn't a function it throws an error?

@@ -40,6 +41,9 @@ var CallbackRegistry = {
* @param {?function} listener The callback to store.
*/
putListener: function(id, registrationName, listener) {
var invariantError = 'Trying to bind an event handler to a non-function for %s';
invariant(typeof listener === 'function', invariantError, registrationName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit for when we figure out exactly what to do: just put the string in here directly. We strip it out in our minification step. You can see how we handle the long line issue (https://github.com/facebook/react/blob/master/src/addons/transitions/ReactTransitionGroup.js#L41-L45 for example)

@toddself
Copy link
Author

@zpao we don't accept pull requests internally that don't have test cases, so it's second hand nature now 😄 But I appreciate the enthusiasm!

@@ -89,3 +96,5 @@ var CallbackRegistry = {
};

module.exports = CallbackRegistry;

require("./mock-modules").register("CallbackRegistry", module);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this doing here? Do we need it? It's not really written to our conventions (specifically relative paths, requiring at the end of a file etc)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So odd. I don't remember putting that line there at all...

This has been resolved and history cleaned.

@petehunt
Copy link
Contributor

CLA is processed, thanks!

@toddself
Copy link
Author

@petehunt thanks for the help with the CLA!

@zpao
Copy link
Member

zpao commented Dec 13, 2013

I think we're just going to let this one live as is. We have a lot of invariants now and I think we'd like to move towards having a distinction between warn and throw invariants. cc @petehunt

@zpao zpao closed this Dec 13, 2013
bvaughn pushed a commit to bvaughn/react that referenced this pull request Aug 13, 2019
This change adds support for element inspecting within `<iframe/>`s.

The iframes are kept in a Set so that we only append listeners once and
clean them up properly. I’ve run a few tests and it seems to behave as
expected.

The fixture includes a cross-origin iframe to make sure we do not error
in this case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

No error checking for binding an event to a missing handler
5 participants