Giter Site home page Giter Site logo

react-event-listener's Introduction

react-event-listener

A React component for binding events on the global scope.

npm version npm downloads Build Status

Dependencies DevDependencies

Installation

npm install react-event-listener

The problem solved

This module provides a declarative way to bind events to a global EventTarget. It's using the React lifecycle to bind and unbind at the right time.

Usage

import React, {Component} from 'react';
import EventListener, {withOptions} from 'react-event-listener';

class MyComponent extends Component {
  handleResize = () => {
    console.log('resize');
  };

  handleScroll = () => {
    console.log('scroll');
  };

  handleMouseMove = () => {
    console.log('mousemove');
  };

  render() {
    return (
      <div>
        <EventListener
          target="window"
          onResize={this.handleResize}
          onScroll={withOptions(this.handleScroll, {passive: true, capture: false})}
        />
        <EventListener target={document} onMouseMoveCapture={this.handleMouseMove} />
      </div>
    );
  }
}

Note on server-side rendering

When doing server side rendering, document and window aren't available. You can use a string as a target, or check that they exist before rendering the component.

Note on performance

You should avoid passing inline functions for listeners, because this creates a new Function instance on every render, defeating EventListener's shouldComponentUpdate, and triggering an update cycle where it removes its old listeners and adds its new listeners (so that it can stay up-to-date with the props you passed in).

Note on testing

In this issue from React, TestUtils.Simulate. methods won't bubble up to window or document. As a result, you must use document.dispatchEvent or simulate event using native DOM api.

See our test cases for more information.

License

MIT

react-event-listener's People

Contributors

avetisk avatar belgattitude avatar darrenscerri avatar greenkeeper[bot] avatar greenkeeperio-bot avatar jaroslav-kubicek avatar jedwards1211 avatar matthoffner avatar oliviertassinari avatar rosskevin avatar tomchentw avatar trysound avatar wojtekmaj avatar wub avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

react-event-listener's Issues

Getting `Can't resolve '@babel/runtime/helpers/builtin/classCallCheck'` after upgrading to Material UI 3.9.2

Here are my dependencies from package.json:

"devDependencies": {
    "@babel/cli": "7.2.3",
    "@babel/core": "7.3.3",
    "@babel/plugin-proposal-class-properties": "7.3.3",
    "@babel/plugin-proposal-decorators": "7.3.0",
    "@babel/plugin-proposal-object-rest-spread": "7.3.2",
    "@babel/preset-env": "7.3.1",
    "@babel/preset-react": "7.0.0",
    "@babel/register": "7.0.0",
    "app-module-path": "2.2.0",
    "autoprefixer": "9.4.8",
    "babel-eslint": "10.0.1",
    "babel-loader": "8.0.5",
    "chai": "4.2.0",
    "clean-webpack-plugin": "1.0.1",
    "css-loader": "2.1.0",
    "enzyme": "3.9.0",
    "enzyme-adapter-react-16": "1.9.1",
    "eslint": "5.14.1",
    "eslint-plugin-react": "7.12.4",
    "file-loader": "3.0.1",
    "jquery-param": "1.0.1",
    "jsdom": "11.11.0",
    "jsonwebtoken": "8.5.0",
    "mocha": "6.0.0",
    "node-sass": "4.11.0",
    "npm-run-all": "4.1.5",
    "postcss": "7.0.14",
    "postcss-loader": "3.0.0",
    "redux-devtools": "3.5.0",
    "redux-devtools-extension": "2.13.8",
    "resolve-url-loader": "3.0.1",
    "sass-loader": "7.1.0",
    "sinon": "7.2.4",
    "style-loader": "0.23.1",
    "stylelint": "9.10.1",
    "stylelint-config-standard": "18.2.0",
    "stylelint-scss": "3.5.3",
    "uglifyjs-webpack-plugin": "2.1.1",
    "url-loader": "1.1.2",
    "webpack": "4.29.5",
    "webpack-clean-obsolete-chunks": "0.4.0",
    "webpack-cli": "3.2.3"
  },
  "dependencies": {
    "@babel/polyfill": "7.2.5",
    "@material-ui/core": "3.9.2",
    "@material-ui/icons": "3.0.2",
    "@material-ui/lab": "3.0.0-alpha.30",
    "anchorme": "1.1.2",
    "bootstrap": "3.3.5",
    "classnames": "2.2.6",
    "crypto-js": "3.1.9-1",
    "googleapis": "15.0.0",
    "history": "4.7.2",
    "ismobilejs": "0.5.1",
    "isomorphic-fetch": "2.2.1",
    "jquery": "3.3.1",
    "lodash": "4.17.11",
    "moment": "2.24.0",
    "prop-types": "15.7.2",
    "query-string": "5",
    "react": "16.8.2",
    "react-autosuggest": "9.4.3",
    "react-bootstrap": "0.32.4",
    "react-color": "2.17.0",
    "react-datepicker": "1.6.0",
    "react-dom": "16.8.2",
    "react-joyride": "1.11.4",
    "react-modal": "3.8.1",
    "react-redux": "5.0.7",
    "react-router-dom": "4.3.1",
    "react-slick": "0.23.2",
    "react-tooltip": "3.9.2",
    "react-ultimate-pagination-bootstrap-3": "1.2.0",
    "react-virtualized": "9.21.0",
    "recharts": "1.5.0",
    "redux": "4.0.1",
    "redux-logger": "3.0.6",
    "redux-thunk": "2.3.0",
    "slick-carousel": "1.8.1",
    "sprintf-js": "1.1.2",
    "validator": "6.2.0"
  }

I tried upgrading the following Material UI packages:

screen shot 2019-02-20 at 11 46 17 am

However, here the are the errors I'm getting when webpack is running:

screen shot 2019-02-20 at 11 48 24 am

When I looked at the react-event-listener.cjs.js file in my node_modules/react-event-listener, I see that it is referencing babel packages with this directory structure:

screen shot 2019-02-20 at 11 51 38 am

It seems to be looking for a builtin directory inside of the babel package. However, when I looked at the babel package in my node_modules, I notice that there isn't a builtin directory under the helpers directory:

screen shot 2019-02-20 at 11 53 20 am

As a test, I modified the react-event-listener.cjs.js file and removed the reference to the builtin directory and webpack seems to compile and my application seems to work.

Can you let me know how I can get rid of this webpack compilation error so that I can successfully upgrade to Material UI 3.9.2?

React 16.0 support.

Not sure if it would require more work than just changing the one line in the package file.

using window[target]

First of all - great component!
Two question though:
is using window[target] not considered antipattern? is this not targeting the DOM itself, instead of the shadow dom, thus breaking the react tree/chain?
Also - is there a way to make the target element a specific react component, instead of a dom element?

An in-range update of enzyme is breaking the build 🚨

Version 2.8.1 of enzyme just got published.

Branch Build failing 🚨
Dependency enzyme
Current Version 2.8.0
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As enzyme is “only” a devDependency of this project it might not break production or downstream projects, but “only” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this 💪


Status Details
  • continuous-integration/travis-ci/push The Travis CI build failed Details
Commits

The new version differs by 33 commits .

  • 8ab9528 v2.8.1
  • 75d1390 Merge pull request #876 from kentcdodds/pr/support-15.5
  • 21f6e7a [Tests] create-react-class should be a static dev dependency.
  • 4464a17 [Tests] move helpers in to test/_helpers dir
  • 22f368f address final comments
  • cc78489 Update error message in react-compat
  • b48e551 Change condition in performBatchedUpdates to a version check
  • 2f957af REACT155 constant is now true for react 15.5 or above
  • f5f6001 Update ReactWrapperComponent to use prop-types package
  • 3ff9832 Update karma cofig to be compatible with [email protected]
  • ec7bbc5 Lint
  • 270ee7f Remove unnecessary tests
  • d6badda Fix import
  • edeb99c Remove dependency on create-react-class
  • b0e2fac Extract batchedUpdates to a function

There are 33 commits in total. See the full diff.

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Possibly unnecessary @babel/runtime?

I noticed Webpack bundles @babel/runtime and I traced it back to this module. Is it necessary to include it in prod build? I'd like to reduce build size and react-event-listener is 1.82kb while @babel/runtime is 2.3kb.

Update @babel/runtime to match material-ui project

Recently material-ui was updated to use babel/[email protected], however this project is pinned to babel/[email protected].

The main issue is that these two versions of babel/runtime are incompatible - so doing a yarn install --flat creates a breaking build :(

Here are all the errors that I am seeing when I try to force babel/[email protected] ... It looks like a couple of things were removed...

ERROR in ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js
Module not found: Error: Can't resolve '@babel/runtime/helpers/builtin/classCallCheck' in 'C:\projects\kalix.ui\client_modules\node_modules\react-event-listener\dist'
 @ ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js 7:38-94
 @ ../client_modules/node_modules/@material-ui/core/Tabs/Tabs.js
 @ ../client_modules/node_modules/@material-ui/core/Tabs/index.js
 @ ../client_modules/node_modules/@material-ui/core/index.es.js
 @ ./app.js
 @ ./index.js
 @ multi ../node_modules/webpack-dev-server/client?http://localhost:3000 ../node_modules/webpack/hot/dev-server.js babel-polyfill index

ERROR in ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js
Module not found: Error: Can't resolve '@babel/runtime/helpers/builtin/createClass' in 'C:\projects\kalix.ui\client_modules\node_modules\react-event-listener\dist'
 @ ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js 8:35-88
 @ ../client_modules/node_modules/@material-ui/core/Tabs/Tabs.js
 @ ../client_modules/node_modules/@material-ui/core/Tabs/index.js
 @ ../client_modules/node_modules/@material-ui/core/index.es.js
 @ ./app.js
 @ ./index.js
 @ multi ../node_modules/webpack-dev-server/client?http://localhost:3000 ../node_modules/webpack/hot/dev-server.js babel-polyfill index

ERROR in ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js
Module not found: Error: Can't resolve '@babel/runtime/helpers/builtin/inherits' in 'C:\projects\kalix.ui\client_modules\node_modules\react-event-listener\dist'
 @ ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js 10:32-82
 @ ../client_modules/node_modules/@material-ui/core/Tabs/Tabs.js
 @ ../client_modules/node_modules/@material-ui/core/Tabs/index.js
 @ ../client_modules/node_modules/@material-ui/core/index.es.js
 @ ./app.js
 @ ./index.js
 @ multi ../node_modules/webpack-dev-server/client?http://localhost:3000 ../node_modules/webpack/hot/dev-server.js babel-polyfill index

ERROR in ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js
Module not found: Error: Can't resolve '@babel/runtime/helpers/builtin/objectSpread' in 'C:\projects\kalix.ui\client_modules\node_modules\react-event-listener\dist'
 @ ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js 13:36-90
 @ ../client_modules/node_modules/@material-ui/core/Tabs/Tabs.js
 @ ../client_modules/node_modules/@material-ui/core/Tabs/index.js
 @ ../client_modules/node_modules/@material-ui/core/index.es.js
 @ ./app.js
 @ ./index.js
 @ multi ../node_modules/webpack-dev-server/client?http://localhost:3000 ../node_modules/webpack/hot/dev-server.js babel-polyfill index

ERROR in ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js
Module not found: Error: Can't resolve '@babel/runtime/helpers/builtin/objectWithoutProperties' in 'C:\projects\kalix.ui\client_modules\node_modules\react-event-listener\dist'
 @ ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js 12:47-112
 @ ../client_modules/node_modules/@material-ui/core/Tabs/Tabs.js
 @ ../client_modules/node_modules/@material-ui/core/Tabs/index.js
 @ ../client_modules/node_modules/@material-ui/core/index.es.js
 @ ./app.js
 @ ./index.js
 @ multi ../node_modules/webpack-dev-server/client?http://localhost:3000 ../node_modules/webpack/hot/dev-server.js babel-polyfill index

ERROR in ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js
Module not found: Error: Can't resolve '@babel/runtime/helpers/builtin/possibleConstructorReturn' in 'C:\projects\kalix.ui\client_modules\node_modules\react-event-listener\dist'
 @ ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js 9:49-116
 @ ../client_modules/node_modules/@material-ui/core/Tabs/Tabs.js
 @ ../client_modules/node_modules/@material-ui/core/Tabs/index.js
 @ ../client_modules/node_modules/@material-ui/core/index.es.js
 @ ./app.js
 @ ./index.js
 @ multi ../node_modules/webpack-dev-server/client?http://localhost:3000 ../node_modules/webpack/hot/dev-server.js babel-polyfill index

ERROR in ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js
Module not found: Error: Can't resolve '@babel/runtime/helpers/builtin/typeof' in 'C:\projects\kalix.ui\client_modules\node_modules\react-event-listener\dist'
 @ ../client_modules/node_modules/react-event-listener/dist/react-event-listener.cjs.js 11:30-78
 @ ../client_modules/node_modules/@material-ui/core/Tabs/Tabs.js
 @ ../client_modules/node_modules/@material-ui/core/Tabs/index.js
 @ ../client_modules/node_modules/@material-ui/core/index.es.js
 @ ./app.js
 @ ./index.js
 @ multi ../node_modules/webpack-dev-server/client?http://localhost:3000 ../node_modules/webpack/hot/dev-server.js babel-polyfill index

Error with Flow 54

Error: node_modules/react-event-listener/src/index.js:49
49: children?: React.Element,
^^^^^^^^^^^^^^^^^^ Element. Property not found in
v-
234: declare export default {|
235: +DOM: typeof DOM,
236: +PropTypes: typeof PropTypes,
...:
248: |};
-^ object type. See lib: /private/tmp/flow/flowlib_5981b62/react.js:234

Error: node_modules/react-event-listener/src/index.js:102
102: class EventListener extends Component {
^^^^^^^^^ identifier Component. Too few type arguments. Expected at least 1
29: declare class React$Component<Props, State = void> {
^^^^^^^^^^^^ See type parameters of definition here. See lib: /private/tmp/flow/flowlib_5981b62/react.js:29

Flow errors with Flow 42.0

With Flow version 42.0, I get a bunch of Flow errors (both in my project using this library, and in a fresh checkout of this library alone)

src/index.js:57
 57:   iteratee: (eventName: string, listener: Function, options?: EventOptions) => any,
                                               ^^^^^^^^ function type. Callable signature not found in
 80:       iteratee(eventName, prop, mergeDefaultEventOptions({ capture }));
                               ^^^^ EventTarget

src/index.js:57
 57:   iteratee: (eventName: string, listener: Function, options?: EventOptions) => any,
                                               ^^^^^^^^ function type. Callable signature not found in
 80:       iteratee(eventName, prop, mergeDefaultEventOptions({ capture }));
                               ^^^^ React$Element

src/index.js:78
 78:       iteratee(eventName, prop.handler, prop.options);
                                    ^^^^^^^ property `handler`. Property cannot be accessed on possibly undefined value
 78:       iteratee(eventName, prop.handler, prop.options);
                               ^^^^ undefined

src/index.js:78
 78:       iteratee(eventName, prop.handler, prop.options);
                                    ^^^^^^^ property `handler`. Property not found in
 78:       iteratee(eventName, prop.handler, prop.options);
                               ^^^^ EventTarget

src/index.js:78
 78:       iteratee(eventName, prop.handler, prop.options);
                                    ^^^^^^^ property `handler`. Property not found in
 78:       iteratee(eventName, prop.handler, prop.options);
                               ^^^^ React$Element

src/index.js:78
 78:       iteratee(eventName, prop.handler, prop.options);
                                                  ^^^^^^^ property `options`. Property cannot be accessed on possibly undefined value
 78:       iteratee(eventName, prop.handler, prop.options);
                                             ^^^^ undefined

src/index.js:78
 78:       iteratee(eventName, prop.handler, prop.options);
                                                  ^^^^^^^ property `options`. Property not found in
 78:       iteratee(eventName, prop.handler, prop.options);
                                             ^^^^ EventTarget

src/index.js:78
 78:       iteratee(eventName, prop.handler, prop.options);
                                                  ^^^^^^^ property `options`. Property not found in
 78:       iteratee(eventName, prop.handler, prop.options);
                                             ^^^^ React$Element

src/index.js:80
 80:       iteratee(eventName, prop, mergeDefaultEventOptions({ capture }));
                               ^^^^ undefined. This type is incompatible with the expected param type of
 57:   iteratee: (eventName: string, listener: Function, options?: EventOptions) => any,
                                               ^^^^^^^^ function type

target={object} breaks snapshot rendering

Hello, thank you for great lib. Unfortunately, i have one problem:

const tree = renderer.create(<EventListener target={window} onBeforeUnloadCapture={() => {}} />).toJSON();
expect(tree).toMatchSnapshot();

The problem is the snapshot printing is trying to serialize whole window/document object and fails. Please consider to allow to pass "window" and "document" as strings again.

React as peer dependency

Thanks for the project, this is a great idea!

Should react be added as a peer dependency to the package.json?

visibilitychange event doesn't return document in 'this'

Nice module.
I'm trying the following

import React from 'react'
import Router from 'react-router'
import { Route, DefaultRoute, RouteHandler } from 'react-router'
import LocalStorageMixin from 'react-localstorage'
import EventListener from 'react-event-listener'

/*
 * Top level Component
 */
let App = React.createClass({
  mixins: [
    EventListener,
    LocalStorageMixin
  ],
  listeners: {
    document: {
      visibilitychange: 'onVisibilityChange'
    }
  },
  onVisibilityChange: function() {
    // the variable this refers to the document object
    console.log('visbility state:', this)
  },
  render() {
    return (
      <RouteHandler />
    )
  }
})

the this object looks like
screenshot 2015-07-28 16 44 35
I was expecting it to return the document object. Which would have document.hidden

Fix @babel/runtime version on v5

Hi! We use a package that depends on react-event-listener in version 5.x. Since Babel broke something in their last beta (beta 56) we have an error. I see you fixed it in the version 6.2 but as we use version 5 we don’t have the fix :(

Would it be possible to create a new version 5.10 that integrates the fix, i.e. fixes @babel/runtime version to 7.0.0-beta.42?

I could actually create a PR, but for that I would need a branch v5… ;)

Thanks!

An in-range update of mocha is breaking the build 🚨

Version 3.4.0 of mocha just got published.

Branch Build failing 🚨
Dependency mocha
Current Version 3.3.0
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As mocha is “only” a devDependency of this project it might not break production or downstream projects, but “only” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this 💪

Status Details
  • continuous-integration/travis-ci/push The Travis CI build failed Details

Release Notes v3.4.0

Mocha is now moving to a quicker release schedule: when non-breaking changes are merged, a release should happen that week.

This week's highlights:

  • allowUncaught added to commandline as --allow-uncaught (and bugfixed)
  • warning-related Node flags

🎉 Enhancements

🐛 Fixes

🔩 Other

Commits

The new version differs by 9 commits0.

  • 7554b31 Add Changelog for v3.4.0
  • 9f7f7ed Add --trace-warnings flag
  • 92561c8 Add --no-warnings flag
  • ceee976 lint test/integration/fixtures/simple-reporter.js
  • dcfc094 Revert "use semistandard directly"
  • 93392dd no special case for macOS running Karma locally
  • 4d1d91d --allow-uncaught cli option
  • fb1e083 fix allowUncaught in browser
  • 4ed3fc5 Add license report and scan status

false

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Target component

Hi there, thanks for the great library!

I want to attach a transitionend event to my component, but I want to avoid using React's synthetic event system because I need to know the specific time the real browser event occurred. For context, this is so I can measure the time between events with the User Timing API.

I have something like this:

      <EventListener
        target={this.transitionEl}
        onTransitionEnd={this.onTransitionEnd.bind(this)}
      >
        <div
          ref={(ref) => { this.transitionEl = ref; }}
        >
// …

This works, but I get a warning because, on the initial render, this.transitionEl is undefined (the ref hasn't been set yet).

Is this safe to do? Do you have any better recommendations?

Thanks!

An in-range update of babel-plugin-transform-react-remove-prop-types is breaking the build 🚨

Version 0.4.4 of babel-plugin-transform-react-remove-prop-types just got published.

Branch Build failing 🚨
Dependency babel-plugin-transform-react-remove-prop-types
Current Version 0.4.3
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As babel-plugin-transform-react-remove-prop-types is “only” a devDependency of this project it might not break production or downstream projects, but “only” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this 💪

Status Details - ❌ **continuous-integration/travis-ci/push** The Travis CI build failed [Details](https://travis-ci.org/oliviertassinari/react-event-listener/builds/227738247?utm_source=github_status&utm_medium=notification)

Release Notes v0.4.4

Fixes / Enhancements

  • fix(flow): support tricky use case with flow and the wrap mode (#105)
// In
type Props = {
  bar?: string,
};

function MyComponent(props: Props) {
return <div {...props} />;
}

// Babel Transformations
[
'babel-plugin-flow-react-proptypes',
'babel-plugin-transform-flow-strip-types',
'babel-plugin-transform-react-remove-prop-types',
]

// Out
function MyComponent(props) {
return React.createElement('div', props);
}

MyComponent.propTypes = process.env.NODE_ENV !== 'production' ? {
bar: require('prop-types').string
} : {};

Commits

The new version differs by 3 commits0.

  • 9de2a21 0.4.4
  • 98e2d54 Merge pull request #105 from oliviertassinari/flow-fix
  • 463d987 fix(flow): use case

false

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

add / removeEventListener passive options?

Thank you for awesome library!

I want to improve the performance of window.onscroll. must use the addEventListener passive option for that.

There are several proposals in the options of how to specify, what do you think?

Pattern 1: Wrapped function

// App.js
import EventListener, { withOptions } from "react-event-listener";

class Example extends Component {
  handleScroll(e) {
    // ...
  }

  render() {
    return (
      <EventListener
        target={window}
        onScroll={withOptions(this.handleScroll, {capture: false, passive: true})}
      />
    );
  }
}

Pass a handler in object form, there is a pattern to specify the options.
I believe that this pattern is good.

  • Pros
    • In the future it can be extended if there was additional flag.
    • It can be implemented with backwards compatibility.
  • Cons
    • ??

Pattern 2: Capture like

<EventListener
  target={window}
  onScrollPassive={this.handleScroll}
/>
  • Pros
    • Simple syntax & API.
    • It can be implemented with backwards compatibility.
  • Cons
    • Additional flag is broken and there. (Example: onScrollCapturePassiveFooBar)

Pattern 3: Pass in component props

<EventListener
  passive
  target={window}
  onScrollPassive={this.handleScroll}
/>
  • Pros
    • Simple syntax & API.
    • In the future it can be extended if there was additional flag.
  • Cons
    • passive options would be across all of the handler. (Example: onResize)

Side note: Polyfill sample of passive options

IE8 for the simple sample has been excluded.

// Check compatible
let supportsPassive = false;

try {
  const options = Object.defineProperty({}, 'passive', {
    get() {
      supportsPassive = true;
    }
  });
  window.addEventListener('test', null, options);
} catch (e) {}

// Usage
function on(target, type, handler, options) {
  let optionsOrCapture = options;

  if (!supportsPassive) {
    optionsOrCapture = options.capture;
  }

  target.addEventListener(type, handler, optionsOrCapture);
}

function off(target, type, handler, options) {
  // ...
}

How does one unit test this component inside our own?

For instance, take the following TypeScript example:

export default class MyComponent extends React.Component<any, any> {

    constructor() {
        super();

        this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
    }

    public render(): JSX.Element {
        return (
            <div>
                <FooComponent />
                <EventListener
                    target="document"
                    onKeyDown={this.handleDocumentKeyDown} />
                <BarComponent />
            </div>
        );
    }

    private handleDocumentKeyDown(event: any): void {
        if (event.keyCode === KeyCodes.Enter) {
            // do something...
        }
    }

}

How do I render MyComponent, create and set a spy function on onKeyDown property of EventListener and simulate that event (with proper key code as parameter) so that I can assert that the spy was called with the expected key code?

I am using Jest (jest.fn() to create spies) and Enzyme (shallow render) on my test suite but if you give me an example with other framework/tools, maybe I can convert it to my own. I just need a push in the right direction...

I've already tried something like the following:

const spy = jest.fn();
const myComponent = shallow(<MyComponent />);
const eventListener = myComponent.find(EventListener).dive();

eventListener.setProps({
    onKeyDown: spy,
});

eventListener.simulate("onKeyDown");

expect(spy).toHaveBeenCalled();

But it was never called... Not sure what I'm doing wrong :(

Keypress doesn't work in Microsoft Edge

Can't seem to make it work in Edge-browser.

<EventListener target='window' onKeyPress={this.handleDocumentClick} />

handleDocumentClick(e) {
  console.log(e) 
}

Works fine in Chrome & FF

Thoughts on a setTimeout property

First, thanks a lot for this declarative event listener approach! It's very nice :)

I found my self needing a global onClick event to listen for when to call a onRequestClose callback to close a Popover component but the listener get there too early and calling onRequestClose on the same click that opened it.

So... I added a quick implementation for setTimeout below that successfully solved my problem. What you think of this new prop, is it viable or am I miss-using the react-event-listener concept?

export default class EventListener extends React.Component {
    static propTypes = {
        ...
        setTimeout: React.PropTypes.number,
    }

    constructor(props) {
        super(props)
    }

    componentDidMount() {
        if (this.props.setTimeout) {
            setTimeout(() => {
                listenersForEach(this.props, (element, eventName, callback) => {
                    on(element, eventName, callback)
                })
            }, this.props.setTimeout)
        } else {
            listenersForEach(this.props, (element, eventName, callback) => {
                on(element, eventName, callback)
            })
        }

Rewrite using the Hook API

We will rewrite the Material-UI codebase using hooks at some point. We might be able to simplify things using the hook API, to investigate.

Handling events in capture phase

Thanks for this component!

I was thinking about the way how events are handled in capture phase - React use onEventXXXCapture, so have you considered this approach? Is it worth to create pull request or is there design decision behind having special capture prop?

IE10 - TypeError: "Cannot call a class as a function"

When rendering this component in IE10, I get a TypeError exception with a message of "Cannot call a class as a function". I get this error using version 0.5.9, but everything seems to work fine using version 0.5.3. I have not tested the versions in between.

It seems that this there is a bug in the transpilation with causes the prototype to not be wired up correctly for IE10.

The error is thrown in react-dom. react-dom wants the following property to be defined in order to use the component as a constructor.

EventListenter.prototype.isReactComponent

In IE10 this expression is undefined. One thing I did notice is that this expression IS defined:

EventListener.prototype.__proto__.isReactComponent

react-dom attempts to render this as a functional component instead of a class component, which is what causes the exception to be thrown.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.