首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ReactJS -向组件添加自定义事件侦听器

ReactJS -向组件添加自定义事件侦听器
EN

Stack Overflow用户
提问于 2016-03-23 22:03:54
回答 4查看 259K关注 0票数 103

在普通的旧式javascript中,我有一个DIV。

代码语言:javascript
复制
and the following javascript code


var myMovie = document.getElementById('my_movie');
myMovie.addEventListener('nv-enter', function (event) {
     console.log('change scope');
});


Now I have a React Component, inside this component, in the render method, I am returning my div. How can I add an event listener for my custom event? (I am using this library for TV apps - navigation )

import React, { Component } from 'react';

class MovieItem extends Component {

  render() {

    if(this.props.index === 0) {
      return (
        
            
            
                {this.props.movieItem.caption.toUpperCase()}
            
        
      );
    }
    else {
      return (
        
            
            
                {this.props.movieItem.caption.toUpperCase()}
            
        
      );
    }
  }

}

export default MovieItem;


Update #1:



I applied all the ideas provided in the answers. I set the navigation library to debug mode and I am able to navigate on my menu items only based on the keyboard (as you can see in the screenshot I was able to navigate to Movies 4) but when I focus an item in the menu or press enter, I dont see anything in the console.

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class MenuItem extends Component {

  constructor(props) {
    super(props);
    // Pre-bind your event handler, or define it as a fat arrow in ES7/TS
    this.handleNVFocus = this.handleNVFocus.bind(this);
    this.handleNVEnter = this.handleNVEnter.bind(this);
    this.handleNVRight = this.handleNVRight.bind(this);
  }

  handleNVFocus = event => {
      console.log('Focused: ' + this.props.menuItem.caption.toUpperCase());
  }

  handleNVEnter = event => {
      console.log('Enter: ' + this.props.menuItem.caption.toUpperCase());
  }

  handleNVRight = event => {
      console.log('Right: ' + this.props.menuItem.caption.toUpperCase());
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this).addEventListener('nv-focus', this.handleNVFocus);
    ReactDOM.findDOMNode(this).addEventListener('nv-enter', this.handleNVEnter);
    ReactDOM.findDOMNode(this).addEventListener('nv-right', this.handleNVEnter);
    //this.refs.nv.addEventListener('nv-focus', this.handleNVFocus);
    //this.refs.nv.addEventListener('nv-enter', this.handleNVEnter);
    //this.refs.nv.addEventListener('nv-right', this.handleNVEnter);
  }

  componentWillUnmount() {
    ReactDOM.findDOMNode(this).removeEventListener('nv-focus', this.handleNVFocus);
    ReactDOM.findDOMNode(this).removeEventListener('nv-enter', this.handleNVEnter);
    ReactDOM.findDOMNode(this).removeEventListener('nv-right', this.handleNVRight);
    //this.refs.nv.removeEventListener('nv-focus', this.handleNVFocus);
    //this.refs.nv.removeEventListener('nv-enter', this.handleNVEnter);
    //this.refs.nv.removeEventListener('nv-right', this.handleNVEnter);
  }

  render() {
    var attrs = this.props.index === 0 ? {"aria-nv-el-current": true} : {};
    return (
      
          
          
              {this.props.menuItem.caption.toUpperCase()}
          
      
    )
  }

}

export default MenuItem;


I left some lines commented because in both cases I am not able to get the console lines to be logged.

Update #2: This navigation library does not work well with React with its original Html Tags, so I had to set the options and rename the tags to use aria-* so it would not impact React.

navigation.setOption('prefix','aria-nv-el');
navigation.setOption('attrScope','aria-nv-scope');
navigation.setOption('attrScopeFOV','aria-nv-scope-fov');
navigation.setOption('attrScopeCurrent','aria-nv-scope-current');
navigation.setOption('attrElement','aria-nv-el');
navigation.setOption('attrElementFOV','aria-nv-el-fov');
navigation.setOption('attrElementCurrent','aria-nv-el-current');
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-03-23 23:04:12

如果您需要处理React尚未提供的DOM事件您必须在挂载组件后添加DOM侦听器:

更新:在React 13、14和15之间,对影响我的答案的API进行了更改。下面是使用React 15和ES7的最新方法。请参见回答历史对于较旧的版本。

代码语言:javascript
复制
class MovieItem extends React.Component {

  componentDidMount() {
    // When the component is mounted, add your DOM listener to the "nv" elem.
    // (The "nv" elem is assigned in the render function.)
    this.nv.addEventListener("nv-enter", this.handleNvEnter);
  }

  componentWillUnmount() {
    // Make sure to remove the DOM listener when the component is unmounted.
    this.nv.removeEventListener("nv-enter", this.handleNvEnter);
  }

  // Use a class arrow function (ES7) for the handler. In ES6 you could bind()
  // a handler in the constructor.
  handleNvEnter = (event) => {
    console.log("Nv Enter:", event);
  }

  render() {
    // Here we render a single  and toggle the "aria-nv-el-current" attribute
    // using the attribute spread operator. This way only a single 
    // is ever mounted and we don't have to worry about adding/removing
    // a DOM listener every time the current index changes. The attrs 
    // are "spread" onto the  in the render function: {...attrs}
    const attrs = this.props.index === 0 ? {"aria-nv-el-current": true} : {};

    // Finally, render the div using a "ref" callback which assigns the mounted 
    // elem to a class property "nv" used to add the DOM listener to.
    return (
       this.nv = elem} aria-nv-el {...attrs} className="menu_item nv-default">
        ...
      
    );
  }

}

Example on Codepen.io
票数 96
EN

Stack Overflow用户

发布于 2016-03-23 22:54:33

你可以使用componentDidMount和componentWillUnmount方法:

代码语言:javascript
复制
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class MovieItem extends Component
{
    _handleNVEvent = event => {
        ...
    };

    componentDidMount() {
        ReactDOM.findDOMNode(this).addEventListener('nv-event', this._handleNVEvent);
    }

    componentWillUnmount() {
        ReactDOM.findDOMNode(this).removeEventListener('nv-event', this._handleNVEvent);
    }

    [...]

}

export default MovieItem;
票数 20
EN

Stack Overflow用户

发布于 2016-03-23 22:55:08

首先,自定义事件本身并不能很好地处理React组件。所以你不能就这么说

在渲染函数中,必须考虑这个问题。

其次,在查看了您正在使用的库的文档之后,该事件实际上会被触发document.body,所以即使它工作了,你的事件处理程序也永远不会触发。

取而代之的是内部componentDidMount在您的应用程序中的某个位置,您可以通过添加以下内容来监听nv-enter

代码语言:javascript
复制
document.body.addEventListener('nv-enter', function (event) {
    // logic
});

然后,在回调函数中,点击一个改变组件状态的函数,或者你想做的任何事情。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36180414

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档