facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
227.63k stars 46.44k forks source link

Is it possible to add multiple event listeners to React component? Is it possible to programmatically assign listener? #2925

Closed dan-codes-16 closed 9 years ago

dan-codes-16 commented 9 years ago

Hello,

Could you please answer the following questions:

Ideally i'm looking for something like addEventListener

It would be great if you could suggest something.

Thank you, Andrei

sebmarkbage commented 9 years ago

No, the React event system doesn't have a way to attach multiple listeners to a single node automatically. You can always chain a callback to your own event emitter if you want to.

I'm curious about your use case. I've never seen the need for this (and I've seen a lot of React components). Could you elaborate a bit? Maybe there's something we're missing that we should support.

dan-codes-16 commented 9 years ago

Thank you for your reply. The idea is to implement form validation mixin having the following functionality:

So I wanted to add handlers to form inputs in componentDidMount and didn't want to overwrite any handlers if they are assign in component previously.

brigand commented 9 years ago

You could use a helper function which behaves like a simpler (less powerful) version of react's mixin strategy.

The minimal example of its use is this:

var a = {foo: function(x){ console.log(x*2) }};
var b = {foo: function(x){ console.log(x*3) }};
var methods = mergeMethods(a, b);
methods.foo(5); // logs 10 and 15 to the console

In a more realistic example, your mixin is probably calling mergeMethods internally while accepting an object from the component's render method. Here getFormProperties would be calling it internally, to ensure if the user passes any of the same handlers to it, that they're called.

This also puts you in a position to accept properties ignored by the native dom components, like onSuccessfullySubmit, while remaining a mixin.

render: function(){
  return <form {...this.getFormProperties({
    onSubmit: function(){  }
  })}></form>;
}

I'm not sure how good of an idea this is, it's just the most direct answer I have, without saying 'just use addEventListener' :-)

More code:

function both(f, g){
  return function(){
    f.apply(this, arguments); g.apply(this, arguments);
  };
}

function mergeMethods(/* ...objs*/){
  var result = {};
  Array.prototype.forEach.call(arguments, function(obj){
    Object.keys(obj).forEach(function(key){
      if (typeof obj[key] !== "function") {
        if (key in result) 
          throw new Error('mergeMethods: non method keys from multiple sources cannot be used, ' + key + ' exists in more than one source');

         result[key] = obj[key];
         return;
      }

      if (result[key]) result[key] = both(result[key], obj[key]);
      else result[key] = obj[key];
    });
  });
  return result;
}
dan-codes-16 commented 9 years ago

Thank you guys, it seems like my case is becoming much more complex from business requirements perspective, so original ask is no longer actual. Also I think that it might be not very secure solution in terms of possible state change conflicts from different event handlers.

Again thank you for the suggestions. I will keep them in mind anyway.

altmind commented 9 years ago

If someone is interested, I packaged solution similar to mergeMethods above in npm package. https://github.com/altmind/react-handlers

Brain2000 commented 5 years ago

Hello, Could you please answer the following questions:

Is it possible to add multiple event listeners to React component? Is it possible to programmatically assign listener?

Ideally i'm looking for something like addEventListener It would be great if you could suggest something. Thank you, Andrei

After learning that React has synthetic events, I was excited that I would be able to add multiple, independent events. But then I discovered that only one of the declared events will be fired, which puzzles me!

Now that hooks are out, injecting an onChange event onto a component should be as easy as adding an additional attribute to a JSX element. But... it's not, because a new onChange event will eat any previous onChange event that might have been on the JSX element, without any error or notification that there are duplicate event props. An example would be adding an additional onChange to an <input> prop in order to automatically control an input mask, i.e. phone number -> (xxx) xxx-xxxx.

I'm not the only one who has to work around this, if you look at the Github project "viewstools/user-masked-input", you'll see they have to create a manual onChange event that you have to manually attach. That makes hooks all the more difficult to make transparent. https://github.com/viewstools/use-masked-input.

If multiple event properties are detected, it would be nice if they would automatically aggregate and use a common event handler, like jQuery does.

design-principles commented 4 years ago

@Brain2000, it will be magic! No one loves magic in programming! But I love this idea.