reactjs - how - react page



ReactJS-Adicionar ouvinte de evento personalizado ao componente (2)

Primeiro, os eventos personalizados não funcionam bem com os componentes React de forma nativa. Então você não pode simplesmente dizer <div onMyCustomEvent={something}> na função de renderização e precisa pensar em um problema.

Em segundo lugar, depois de dar uma olhada na documentação da biblioteca que você está usando, o evento é realmente disparado em document.body , portanto, mesmo que funcionasse, seu manipulador de eventos nunca seria acionado.

Em vez disso, dentro de componentDidMount em algum lugar do seu aplicativo, você pode ouvir o nv-enter adicionando

document.body.addEventListener('nv-enter', function (event) {
    // logic
});

Em seguida, dentro da função de retorno de chamada, pressione uma função que altera o estado do componente ou o que você deseja fazer.

https://src-bin.com

No javascript antigo simples, tenho o DIV

<div class="movie" id="my_movie">

e o seguinte código javascript

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

Agora eu tenho um componente React, dentro desse componente, no método render, estou retornando minha div. Como posso adicionar um ouvinte de evento para o meu evento personalizado? (Estou usando esta biblioteca para aplicativos de TV - https://github.com/ahiipsa/navigation )

import React, { Component } from 'react';

class MovieItem extends Component {

  render() {

    if(this.props.index === 0) {
      return (
        <div aria-nv-el aria-nv-el-current className="menu_item nv-default">
            <div className="indicator selected"></div>
            <div className="category">
                <span className="title">{this.props.movieItem.caption.toUpperCase()}</span>
            </div>
        </div>
      );
    }
    else {
      return (
        <div aria-nv-el className="menu_item nv-default">
            <div className="indicator selected"></div>
            <div className="category">
                <span className="title">{this.props.movieItem.caption.toUpperCase()}</span>
            </div>
        </div>
      );
    }
  }

}

export default MovieItem;

Atualização # 1:

Eu apliquei todas as idéias fornecidas nas respostas. Defino a biblioteca de navegação no modo de depuração e consigo navegar nos itens de menu apenas com base no teclado (como você pode ver na captura de tela, consegui navegar no Movies 4), mas quando foco um item no menu ou pressione enter, não vejo nada no 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 (
      <div ref="nv" aria-nv-el {...attrs} className="menu_item nv-default">
          <div className="indicator selected"></div>
          <div className="category">
              <span className="title">{this.props.menuItem.caption.toUpperCase()}</span>
          </div>
      </div>
    )
  }

}

export default MenuItem;

Deixei algumas linhas comentadas porque, em ambos os casos, não consigo registrar as linhas do console.

Atualização 2: esta biblioteca de navegação não funciona bem com o React com suas tags HTML originais, por isso tive que definir as opções e renomear as tags para usar aria- * para que não causasse impacto no 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');

Answer #1

Se você precisar manipular eventos DOM que ainda não foram fornecidos pelo React, será necessário adicionar ouvintes do DOM após a montagem do componente:

Atualização: entre as Reações 13, 14 e 15 foram feitas alterações na API que afetam minha resposta. Abaixo está a última maneira de usar o React 15 e o ES7. Veja o histórico de respostas para versões mais antigas.

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 <div> and toggle the "aria-nv-el-current" attribute
    // using the attribute spread operator. This way only a single <div>
    // 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 <div> 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 (
      <div ref={elem => this.nv = elem} aria-nv-el {...attrs} className="menu_item nv-default">
        ...
      </div>
    );
  }

}

Exemplo no Codepen.io





react-jsx