Reagisci, ineffienze di bind una nuova function per each evento

Il mio amico e io stiamo avendo un argomento. Nell'interesse della piena divulgazione, sono io che è un grande fan di React ei suoi benefici.

Nei componenti React, quando si collega un evento DOM a ciascun elemento di un elenco di elementi, il model tradizionale deve bind() il gestore di clic generico ai valori che si desidera passare a tale function come parametri. Come scritto di seguito:

 <button onClick={this.onButtonClick.bind(this, buttonIndex)}></button> 

where buttonIndex è un valore che cambia quando l'elenco dei pulsanti viene ripetuto. Questo pattern consente a onButtonClick di essere generico e si aspetta che buttonIndex sia un parametro. Così:

 onButtonClick: function(buttonIndex) { ... some logic } 

Il mio amico sostiene che questo modo di fare le cose è estremamente inefficiente. Ciò richiede che una nuova function venga creata e mantenuta in memory per gestire l'evento di ciascun button. Sono d'accordo con il suo punto, ma ritengo che la React devs non incoraggiasse questo model nei loro documenti ( alless due volte ) se la biblioteca non gestisse in modo efficiente gli events ei loro gestori.

Il model che ha usato per evitare questo è stato quello di utilizzare l'attributo di data- e get il valore (in questo esempio, buttonIndex ) fuori dall'elemento DOM stesso:

 <button data-buttonIndex={buttonIndex} onClick={this.onButtonClick}></button> 

 onButtonClick: function() { var buttonIndex = $(this).data('buttonIndex'); ...some logic } 

Ancora una volta, sono certo che sono il ventilatore React. Ma questo è sbagliato, per due ragioni:

  1. Ottenere i valori fuori dal DOM per passare i dati in giro (come stato ) sconfigge lo scopo di React in molti modi, giusto?
  2. data- attributi sono estremamente ambigui a mio avviso. Possono essere impostati da diversi luoghi (HTML, JS, PHP, ecc.). E non suggeriscono alcun scopo implicito. Questi "dati" potrebbero essere usati ovunque, (JS, CSS, ecc.)

React fa una magia speciale per essere efficace con i suoi events DOM? E se no, c'è un model alternativo che non utilizza l'attributo dei data- e è più esplicito sul suo utilizzo?

Non sono sicuro che questa sia una buona idea, ma … ricorda!

 class Foo { constructor(){ this.getClickHandler = _.memoize(this.getClickHandler); } getClickHandler(index){ return (event) => { doSomething(); }; } render(){ // ... <button onClick={this.getClickHandler(index)}>Click me</button> // ... } } 

In questo modo si evita la creazione di una nuova function, evita l'attribuzione dei dati e evita il costo di esecuzione di una ricerca di qualcosa in casa.


Non credo di aver mai profilato e trovato la creazione di funzioni in rendering per essere un problema. Questo è sicuramente qualcosa che dovresti ottimizzare solo quando i numbers ti dicono di farlo.

Penso che in generale funzioni vincolanti direttamente in render sia il modo idiomatico perché lo fanno nei documenti come indicato e nella nostra esperienza non è stato significativamente less performante. Tuttavia, ci sono casi in cui non si desidera ribudire la function su each rendering, ad esempio se si sta confrontando puntelli in shouldComponentUpdate (come con PureRenderMixin ). Per fare qualcosa di molto simile come suggerisce il tuo amico ma senza guardare il DOM con jQuery (e credo che sia un model comune) puoi passare l'indice come un prop.

 class Parent extends React.Component { render() { return [...some arrays].map((item, index) => { return <Child item={item} index={index} />; }); } } class Child extends React.Component { constructor() { super(); this.handleClickButton = this.handleClickButton.bind(this); } handleClickButton() { // use this.props.index here } render() { return <button onClick={this.handleClickButton}></button>; } } 

Nota quando si utilizzano classi ES6 è necessario legarsi manualmente in constructor poiché accedete a this.props . Non è necessario se utilizzi React.createClass . Maggiori informazioni sulle classi ES6 in React docs qui.