2015-10-01 10 views
14

Sto animando diversi componenti React.js in base alla loro posizione nella finestra. Se il componente si trova nella finestra, animare l'opacità a 1, se non è nella finestra, animare la sua opacità a 0. Sto usando le proprietà top e bottom per determinare se il componente si trova all'interno della finestra.Best practice React.js per quanto riguarda l'ascolto degli eventi della finestra dai componenti

ComponentA mostra il pattern che ho seguito per gli altri componenti B, C e D. Ciascuno sta ascoltando l'evento di scorrimento window.

È questo il modo "React" per fare ciò da ciascun componente che deve dover aggiungere un listener di eventi allo window? Ascoltatori di eventi di scorrimento multipli nella stessa finestra?

Oppure c'è un modo migliore aggiungendo il listener di eventi di scorrimento alla finestra una volta sul componente proprietario Home? Quindi i componenti figlio propri possono ancora sapere dove si trovano nel DOM utilizzando getBoundingClient()?

Home = React.createClass({ 
render: function() { 
    <div> 
     <ComponentA /> 
     <ComponentB /> 
     <ComponentC /> 
     <ComponentD /> 
    </div> 
    }; 
}); 

ComponentA = React.createClass({ 
    componentDidMount: function() { 
    window.addEventListener('scroll', this.handleScroll); 
}, 
    componentWillUnmount: function() { 
    window.removeEventListener('scroll', this.handleScroll); 
    }, 

handleScroll: function() { 
    var domElement = this.refs.domElement.getDOMNode(); 
    this.inViewPort(domElement); 
}, 

inViewPort: function(element) { 
    var elementBounds = element.getBoundingClientRect(); 
    (elementBounds.top <= 769 && elementBounds.bottom >= 430) ? TweenMax.to(element, 1.5, { opacity: 1 }) : TweenMax.to(element, 1.5, { opacity: 0 }); 
}, 
render: function() { 
    return (/* html to render */); 
} 

}); 
+0

Può un componente di alto livello come reagire-router o Redux di collegare fattibile? – earthdan

risposta

22

Ci sono diversi modi per farlo. Uno è attraverso la composizione:

var React = require("react"); 
var _ = require("underscore"); 

var ScrollWrapper = React.createClass({ 
    propTypes: { 
     onWindowScroll: React.PropTypes.func 
    }, 

    handleScroll: function(event) { 
     // Do something generic, if you have to 
     console.log("ScrollWrapper's handleScroll"); 

     // Call the passed-in prop 
     if (this.props.onWindowScroll) this.props.onWindowScroll(event); 
    }, 

    render: function() { 
     return this.props.children; 
    }, 

    componentDidMount: function() { 
     if (this.props.onWindowScroll) window.addEventListener("scroll", this.handleScroll); 
    }, 

    componentWillUnmount: function() { 
     if (this.props.onWindowScroll) window.removeEventListener("scroll", this.handleScroll); 
    } 
}); 

var ComponentA = React.createClass({ 
    handleScroll: function(event) { 
     console.log("ComponentA's handleScroll"); 
    }, 

    render: function() { 
     return (
      <ScrollWrapper onWindowScroll={this.handleScroll}> 
       <div>whatever</div> 
      </ScrollWrapper> 
     ); 
    } 
}); 

Ora, è possibile inserire la logica generica nel componente ScrollWrapper, e improvvisamente diventa riutilizzabile. È possibile creare un ComponentB che esegue il rendering di ScrollWrapper proprio come fa ComponentA.

Per soddisfare il tuo esempio, forse dovrai passare lo ScrollWrapper alcuni oggetti aggiuntivi da ComponentA. Forse gli passerai un sostegno che contiene un'istanza dello ref per richiamare la tua logica. Potresti anche passargli alcune opzioni o argomenti per personalizzare l'interpolazione o i limiti. Non ho codificato nulla di tutto ciò perché penso che lo capirai e sarai in grado di personalizzarlo/scriverlo da solo con la base che ho fornito.

L'altro modo per ottenere questo tipo di cose è attraverso un Mixin. Sebbene, si parli molto di se i Mixin sono buoni o cattivi, e potrebbero anche essere deprecati da React in futuro? Puoi leggere qualcosa su questo e decidere da te cosa ne pensi.

+0

per flusso unidirezionale, separazione di effetti/problemi collaterali, ridondanza ridotta, riutilizzo ulteriore –

1

Definirei sicuramente un listener/componente di eventi. L'ideologia consiste nell'avere componenti separati che possono essere riutilizzati e collocati "ovunque" nell'applicazione - per minimizzare la ridondanza del codice.

L'approccio per mantenere un listener di eventi per compenent è quindi valido.

12

Ecco uno snippet di codice più semplice che dovrebbe funzionare come richiesto. Manca il binding this, quindi, quando esegui window.addEventListener('scroll', this.handleScroll); stai puntando in realtà this all'oggetto finestra.

Invece è necessario associarlo al costruttore. La speranza è

class Home extends Component { 
    constructor(props) { 
    super(props) 
    this.handleScroll = this.handleScroll.bind(this); 
    } 
    componentDidMount() { 
    window.addEventListener('scroll', this.handleScroll); 
    } 
    componentWillUnmount() { 
    window.removeEventListener('scroll', this.handleScroll); 
    } 
    handleScroll(e) { 
    console.log('scroll event'); 
    console.log(e); 
    } 

    render() { 
    return (
    <div> 
     <ComponentA /> 
     <ComponentB /> 
     <ComponentC /> 
     <ComponentD /> 
    </div> 
    ); 
    } 
} 

Un'altra opzione è la sotto, entrambe le opzioni devono lavorare :)

class Home extends Component { 
    componentDidMount() { 
    window.addEventListener('scroll', this.handleScroll.bind(this)); 
    } 
    componentWillUnmount() { 
    window.removeEventListener('scroll', this.handleScroll.bind(this)); 
    } 
    handleScroll(e) { 
    console.log('scroll event'); 
    console.log(e); 
    } 

    render() { 
    return (
    <div> 
     <ComponentA /> 
     <ComponentB /> 
     <ComponentC /> 
     <ComponentD /> 
    </div> 
    ); 
    } 
} 
+0

Significa che riceviamo 4 eventHandlers per l'evento di scorrimento per ComponentiA, B e così via? –

+0

No @AksanaTolstoguzova c'è solo 1 gestore di eventi per l'evento scroll – MCSLI

Problemi correlati