2015-01-20 8 views
24

Mogę dołączyć moją funkcję obsługi zdarzeń do komponentu React. Czy istnieje sposób na uzyskanie odniesienia do tego komponentu wewnątrz handera wydarzeniami?Uzyskaj odwołanie do komponentu React w module obsługi zdarzeń

var Foobar = React.createClass({ 
    action: function() { 
     // ... 
    }, 
    render: function() { 
     var child = React.Children.only(this.props.children), 
      props = _.omit(this.props, 'children'); 
     return React.addons.cloneWithProps(child, props); 
    } 
}); 

var App = React.createClass({ 
    handleMouseEnter: function (event) { 
     // How to get reference to Foobar without using this.refs['foo']? 
     // I need to call *action* on it. 
    }, 
    render: function() { 
     return (
      <div> 
       <Foobar ref="foo" onMouseEnter={this.handleMouseEnter}> 
        ... 
       </Foobar> 
      </div> 
     ); 
    } 
}); 
+1

Dlaczego nie zdefiniujesz 'handleMouseEnter' wewnątrz komponentu' Foobar' i nie uzyskasz dostępu do niego przez 'this'? – daniula

+0

@daniula Ponieważ metoda 'Foobar.action' może być wywołana w wyniku zdarzenia' onClick', a nie tylko 'onMouseEnter'. – vbarbarosh

+1

'action' należy zdefiniować na instancji Foobar. Czy 'this.refs.foo.action()' nie działa dla ciebie? –

Odpowiedz

32

Chyba rozumiem vbarbarosh pytanie jest pytaniem, a przynajmniej miałem podobną, która doprowadziła mnie do tego postu. Więc jeśli to nie odpowiada na oryginalne pytanie, mam nadzieję, że może pomóc innym, którzy tu lądują.

W moim przypadku mam komponent React z n liczbę dzieci do definiowania opcji konfiguracyjnych dla akcji interfejsu użytkownika. Każde dziecko ma inny ref identyfikujący jaką opcję konfiguracyjną reprezentuje dane wejście i chcę mieć możliwość bezpośredniego dostępu do ref, więc mogę wtedy wywołać metody wyeksponowane na moim komponencie potomnym. (Mogłem narazić attrs danych i używać jQuery wyodrębnić, ale to wydaje się dużo dodatkowych obręcze & problemów z wydajnością)

Moja pierwsza próba była to:

... 
<Config ref="showDetails" onChange={this.handleChange} /> 
<Config ref="showAvatar" onChange={this.handleChange} /> 
... 

Idealnie chciałem związać wszystko zmień zdarzenia na jedną procedurę obsługi, a następnie wyodrębnij wartość ref z obiektu docelowego, który wywołał zdarzenie. Niestety wysłany SyntheticEvent ma nie zapewnić sposób, aby uzyskać wartość docelową celu, więc nie mogę nawiązać bezpośredniego połączenia z this.ref[name].methodIWantToCall().

Co znalazłem był artykuł w docs reagować, które prowadzą mnie do rozwiązania:

https://facebook.github.io/react/tips/communicate-between-components.html

Co możemy zrobić, to wykorzystać JavaScript wiążące i przekazać dodatkowe argumenty.

... 
<Config ref="showDetails" onChange={this.handleChange.bind(this, 'showDetails')} /> 
... 

Teraz w moim obsługi uzyskać dane dodawania i mogą uzyskać dostęp do moich pozycje literaturowe:

handleChange: function(refName, event) { 
    this.refs[refName].myMethodIWantToCall() 
} 

Sztuką jest to, że podczas wiązania, kolejność argumentów jest zmieniany i pierwszy argument jest teraz wartość bound przekazane, a zdarzenie jest teraz drugim argumentem. Mam nadzieję, że pomaga!

+4

To jest eleganckie rozwiązanie, jednak jest zniechęcane ze względu na wydajność. Zobacz https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md –

+1

Podobnie jak wiele rzeczy w React, tylko dlatego, że są zniechęcone, nie oznacza to, że zawsze jest kiepski pomysł. Obawa związana z zamknięciami w metodach renderowania ma znaczenie tylko wtedy, gdy: tworzysz odwołania, które powodują, że program obsługi nie jest zbiorem śmieci i/lub tworzysz wiele tego komponentu (i/lub może, jeśli komponent ponownie renderuje obłąkane ilość razy). Zasadniczo koszt wykonania metody związanej jest ** mały **; to tylko problem, gdy jest on złożony. – machineghost

+0

Odniesienia do napisów są teraz przestarzałe: https://facebook.github.io/react/docs/refs-and-the-dom.html –

4

handleMouseEnter w przykładzie zaproponowałeś (i wyjaśnienia, że ​​onClick byłaby przekazywana do obsługi foobar) jest domyślnie automatycznie związany React do kontekście przykład App w obu przypadkach.

Mając to na uwadze, this.refs.foo lub this.refs['foo'] powinno działać dobrze w kontekście, który opisałeś i byłoby właściwym podejściem.

Bardziej czyste rozwiązanie zakładając, że nie ma istotnych powodów, aby trzymać się obsługi w App byłoby utrzymać obsługi całości zawartej w foobar, coś takiego:

var Foobar = React.createClass({ 
    action: function() { 
     // ... 
    }, 
    render: function() { 
     var child = React.Children.only(this.props.children), 
      props = _.omit(this.props, 'children'); 
     return (
      <div onClick={this.action} onMouseEnter={this.action}> 
       React.addons.cloneWithProps(child, props); 
      </div> 
     ); 
    } 
}); 

var App = React.createClass({ 
    render: function() { 
     return (
      <Foobar /> 
     ); 
    } 
}); 
+0

Pytanie brzmiało: "Jak uzyskać referencję (wewnątrz programu obsługi zdarzeń) do' Foobar' bez użycia 'this.refs ['foo']'? ". To nie jest to, czego potrzebuję. – vbarbarosh

+0

Czy możesz podać dalszy kontekst? this.refs jest jedyną poprawną i jedyną możliwą opcją w React. Jaki jest dokładny scenariusz, który oznacza, że ​​potrzebujesz alternatywnego mechanizmu do korzystania z prawidłowo wbudowanej funkcjonalności zaprojektowanej do odwoływania się do komponentów potomnych? –

4

Musisz propagują obsługi do element główny składnik swojego dziecka, coś takiego:

var Foobar = React.createClass({ 
    action: function (e) { 
     this.props.onClick(this); 
    }, 
    render: function() { 
     return <div onClick={this.action}>{this.props.children}</div>; 
    } 
}); 

var App = React.createClass({ 
    handleMouseEnter: function (foobar) { 
     console.log(foobar); 
    }, 
    render: function() { 
     return (
      <Foobar ref="foo" onClick={this.handleMouseEnter} /> 
     ); 
    } 
}); 
+0

Zdecydowanie najprostszy sposób, aby to osiągnąć. Dzięki! – TFischer

0

Jeśli programmer został dodany programowo, można przekazać komponent jako parametr po prostu przez zawijanie wywołania zwrotnego procedury obsługi za pomocą innej funkcji pod adresem addEventListener.

mam ten przykład używając zdarzenie przewijania:

componentDidMount() { 
    document.getElementById('theElementId').addEventListener('scroll', (e) => { 
     this.handleScroll(e, this); 
    }); 
} 

handleScroll(event, _self) { 
    // Now you can access to the element using the param _self 
} 

render() { 
    return (
     <div id="theElementId"></div> 
    ) 
} 

Inną opcją jest użycie metody wiązania, które zmieni wartość this:

componentDidMount() { 
    document.getElementById('theElementId').addEventListener('scroll', this.handleScroll.bind(this)); 
} 

handleScroll(event) { 
    // Now you can access to the element using the param this 
} 
0

Dobrze patrząc na komponencie App, możesz spróbować:

var App = React.createClass({ 
handleMouseEnter: function (event) { 
    // reference it by using: this.refs[event._targetInst._currentElement.ref] 
    // same result as calling: this.refs.foo 
    console.log(this.refs[event._targetInst._currentElement.ref]) 
}, 
render: function() { 
    return (
     <div> 
      <Foobar ref="foo" onMouseEnter={this.handleMouseEnter}> 
       ... 
      </Foobar> 
     </div> 
     ); 
    } 
}); 

Mam nadzieję, że to pomoże. :) Używam również metody zapisywania/deklarowania komponentów reakcji ES6, która również nieco zmienia zachowanie "tego". Nie jestem pewien, czy to też może odgrywać tu rolę.

Powiązane problemy