2015-10-01 3 views
14

私はいくつかのReact.jsコンポーネントをビューポート内の位置に基づいてアニメーション化しています。コンポーネントがビューポート内にある場合は、不透明度を1にアニメーション化し、ビューポートにない場合は不透明度を0にアニメーションします。コンポーネントがビューポート内にあるかどうかを判断するのにgetBoundingClient()topおよびbottomプロパティを使用しています。React.jsコンポーネントからのウィンドウイベントのリスニングに関するベストプラクティス

コンポーネントAは、他のB、C、およびDコンポーネントのパターンIを示しています。彼らはそれぞれwindowスクロールイベントを待ち受けています。

これは、各コンポーネントがイベントリスナーをwindowに追加する必要があることによってこれを行うための「リアクション」方法ですか?同じウィンドウ上の複数のスクロールイベントリスナー?

または、スクロールイベントリスナーをHome所有者コンポーネントのウィンドウに一度追加すると良いでしょうか?次に、所有者の子コンポーネントは、getBoundingClient()を使用してDOM内のどこにいるかを知ることができますか?

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

に動作するはずされ、それが反応し、ルータや再来のような高レベルのコンポーネントが実行可能に接続することを願って? – earthdan

答えて

22

これを行う方法はいくつかあります。一つは、組成物を通じて次のとおりです。

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> 
     ); 
    } 
}); 

さて、あなたはScrollWrapperコンポーネントで、あなたの一般的なロジックを置くことができ、そして突然、それが再利用可能になります。 ScrollWrapperComponentAと同じようにレンダリングするComponentBを作成できます。

あなたの例を満たすために、ScrollWrapperの追加の小道具をComponentAから渡す必要があります。たぶんあなたはあなたのロジックを呼び出すrefのインスタンスを含む小道具を渡すでしょう。トゥイーンまたは境界をカスタマイズするためのオプションや引数を渡すことさえできます。私はあなたがそれを理解し、私が提供したベースであなた自身のためにそれをカスタマイズ/書くことができると思うので、これをコード化しなかった。

このようなことを達成するもう1つの方法は、ミックスインです。 Mixinsが良かったり悪かったりするのかどうかについての話はたくさんありますが、将来Reactによって廃止される可能性もあります。あなたはこれについていくつかの読書をし、自分の考えを決めることができます。

+0

単方向のフロー、副作用/懸念の分離、冗長性の減少、再利用の増加 –

1

私は間違いなく1つのイベントリスナー/コンポーネントを追加します。イデオロギーは、コードの冗長性を最小限に抑えるために、再利用してアプリケーションのどこにでも配置できるコンポーネントを分離することです。

したがって、compnenentごとにイベントリスナーを保持するあなたのアプローチは有効です。

12

ここでは、必要に応じて機能する必要がある、より簡単なコードスニペットを示します。 window.addEventListener('scroll', this.handleScroll);を実行すると、実際にthisをウィンドウオブジェクトに指しているときに、thisバインディングが欠落しています。

代わりに、これをコンストラクタでバインドする必要があります。

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> 
    ); 
    } 
} 

別のオプションは、以下の、両方のオプションが:)

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

コンポーネントA、Bなどのスクロールイベントに対して4つのeventHandlerを取得することはできますか? –

+0

いいえ@AksanaTolstoguzovaスクロールイベントのイベントハンドラは1つだけです – MCSLI

関連する問題