web-dev-qa-db-ja.com

React.jsサーバーサイドレンダリングとイベントハンドラー

React.jsの使用方法を習得しており、イベントハンドラーの使用にいくつか問題があります。最後の質問は、サーバー側のレンダリングを使用して、イベントハンドラーをクライアントに自動的に送信することは可能ですか?

これが私の例です:サーバーサイドをレンダリングしてクライアントに送信するindex.jsxがあります

var React = require("react");
var DefaultLayout = require("./layout/default");

var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false}; 
  }, 
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  }, 
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  } 
});

var IndexComponent = React.createClass({
   render: function(){
       return (
           <DefaultLayout title={this.props.name}>
                <div>
                        <h1>React Test</h1>
                </div>

                <div id="testButton">
                    <LikeButton/>
                </div> 

                <script type="text/babel" src="/js/react.js"></script>
           </DefaultLayout>
       )
   }   
});

しかし、「いいねボタン」には何の相互作用もありません。クリックで何かを実行するには、このコードをクライアント側に追加する必要があります。

var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('testButton')
);

私はreact.jsから始めただけで、ここでいくつかの主要な概念が欠けているだけかもしれません。しかし、どうしてreact.jsは、ページサーバー側をレンダリングするときにコード(クライアントに手動で追加する必要がある)を作成するだけではないのですか?このように、私は冗長なコードを持っています、そしてこれはより大きなアプリケーションでは混乱になるだろうと感じています。少なくともreact.jsは、2つのLikeButtonを描画するのではなく、作成した1つのサーバー側をクライアント側コンポーネントに「バインド」するのに十分なほどスマートです。

22
Jodo

クライアント側のインタラクティブReactアプリの場合、アプリのクライアント側もレンダリングする必要があります。通常、このコードはサーバーで実行するコードと同じですしたがって、冗長はありませんcode。これは同じコードです。クライアントとサーバーの両方でレンダリングするのはやり過ぎかもしれませんが、パフォーマンスとSEOの観点からは完全に理にかなっています。

ReactDOMServer.renderToString(<MyApp foo={bar} />)は基本的に、マークアップ付きの文字列をレンダリングするだけです。 JavaScriptや魔法はありません。単に古いHTMLです。ただし、レンダリングされたマークアップには多くのReact ID属性があり、後でクライアントで使用されて初期仮想DOMを生成してイベントをアタッチします。

アプリケーションをクライアントで再度レンダリングするとき、サーバー側でレンダリングされたマークアップがサーバーに挿入された同じDOM要素で、Reactはアプリケーション全体を再描画する必要はありません。新しい仮想DOMツリーを作成し、初期の仮想DOMツリーと比較し、必要に応じてDOM操作を実行します。この仮想DOMの概念により、React同じプロセスで、アプリケーションで定義したイベントリスナーは、既にレンダリングされたマークアップにアタッチされます。

これはすべて非常に高速に行われます。また、サーバー側でレンダリングされたページ(Varnishなどを使用してサーバーにキャッシュできる)の利点があり、検索エンジンがクロールし、ユーザーは最初のレンダリングを表示するために何かを待つ必要がなく、ページ基本的に、JavaScriptを無効にしているユーザー向けに機能します。

23
dannyjolie

この動作は、正確にサーバー側のレンダリングが原因です。まず、クライアント側とサーバー側の両方でまったく同じコードを実行する必要があります。これは、同型アプリケーションと呼ばれるものです。サーバーとクライアントの両方で実行されるもの。
つまり、ReactDOM.renderToString(<Component>)を実行すると、HTMLのみが文字列としてレンダリングされます。コンポーネントのrenderメソッドが評価され、初期レンダリングに必要なHTMLが生成されます。
同じコードがクライアントで実行されると、reactはレンダリングされたHTMLを検索し、JSを必要な場所に添付します。 Reactはこのように賢いので、クライアント側ですべてを再度レンダリングすることはありません。コードを評価し、react-idの各DOM要素に基づいてすべてのコードを添付する場所を特定するだけです。が与えられます(reactアプリの要素を検査すると、react-idになります)

同じものを2回レンダリングすることの利点は何でしょうか?
そして答えはユーザーによるperceived loading timeです。また、JSを無効にしたユーザーのための最小限の表示。

クライアントレンダリングアプリケーション
これが、クライアントのみでレンダリングされたアプリケーションの動作方法です。 (レンダリングされたクライアントReactアプリケーションも)

client rendered app

ユーザーは、すべてのスケルトンHTML、JSバンドル(多くの場合かなり大きい)の後にのみコンテンツを表示し、データがフェッチされて評価されます。つまり、すべてが読み込まれるまで、ユーザーはしばらくの間、スピナーまたは読み込み画面を見つめる必要があります。

同形アプリケーション(クライアントとサーバーの両方で実行されます)
同型アプリケーションの仕組み、
server rendered app
この場合、サーバーはコンポーネントを評価してfullHTMLを生成します。また、HTMLがダウンロードされるとすぐにコンテンツが表示されます。 アプリが完全に機能するのは、JSバンドルもダウンロードして評価した後のみです。 JSは両側で実行する必要があります
したがって、ユーザーは以前よりもはるかに速くコンテンツを見ることができます。したがって、知覚される読み込み時間の大幅な減少。

33
Jeff P Chacko