React.js 服务器端渲染和事件处理程序

问题描述 投票:0回答:4

我正在学习使用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足够聪明,不会绘制两个LikeButton,而是将服务器端创建的一个“绑定”到客户端组件。

javascript node.js reactjs event-handling
4个回答
40
投票

此行为是由于服务器端渲染到底是什么造成的。 首先,您必须在客户端和服务器端运行完全相同的代码。这就是所谓的同构应用程序。一种同时在服务器和客户端上运行的工具。
因此,执行

ReactDOM.renderToString(<Component>)
时,只有 HTML 会呈现为字符串。评估组件的渲染方法并生成初始渲染所需的 HTML。
当相同的代码在客户端运行时,React 会查找渲染的 HTML 并在需要的位置附加 JS。 React 在这方面很聪明,它不会在客户端重新渲染所有内容。只需评估代码并根据给定的每个 DOM 元素确定将代码附加到的位置即可。 (如果您检查任何反应应用程序的元素,您将反应ID)

现在有人可能会问,将同一事物渲染两次有什么好处?

用户的答案是

react-id
。还为禁用 JS 的用户提供了一些最低限度的查看。


客户端渲染的应用程序

这就是纯客户端呈现的应用程序的工作原理。 (客户端也渲染了 React 应用程序)

client rendered app 用户只有在所有框架 HTML、JS 包(通常很大)以及数据被获取和评估之后才会看到内容。这意味着用户通常必须盯着旋转器或加载屏幕一段时间,直到所有内容都加载完毕。

同构应用程序(在客户端和服务器上运行)

同构应用程序如何工作,

server rendered app 在这种情况下,服务器通过评估您的组件来生成full
HTML。下载 HTML 后,用户将立即看到内容。 尽管只有在下载并评估 JS 包后应用程序才能完全运行。所以JS两边都要跑 因此,用户看到内容的速度比以前快得多。因此,感知加载时间大幅减少。


29
投票
因此没有冗余代码

。这只是相同的代码。您可能会问自己,在客户端和服务器上进行渲染是否可能有些过大,但从性能和 SEO 的角度来看,这是非常有意义的。

perceived loading time

基本上只是渲染带有标记的字符串。那里没有 JavaScript 或任何魔法。只是普通的旧 HTML。但是,渲染的标记具有许多 React ID 属性,稍后在客户端上使用这些属性来生成初始虚拟 DOM 和附加事件。


当您在客户端上再次渲染应用程序时,在服务器端渲染标记被注入到服务器上的同一个 DOM 元素上,React 不需要重新绘制整个应用程序。它只是创建一个新的 Virtual DOM 树,将其与初始 Virtual DOM 树进行比较,并执行必要的 DOM 操作(如果有)。虚拟 DOM 的概念首先就是让 React 如此快速的原因。在同一过程中,您在应用程序中定义的任何事件侦听器都将附加到已呈现的标记。

所有这一切都发生得很快。而且您可以享受服务器端渲染页面(可以使用 Varnish 或类似的东西缓存在服务器上)的好处,搜索引擎将抓取该页面,用户无需等待任何内容即可查看初始渲染,并且页面基本上适用于禁用了 javascript 的用户。


0
投票
ReactDOMServer.renderToString(<MyApp foo={bar} />)

替换为

ReactDOM.render
您也可以在SSR和CSR中使用相同的LikeButton文件,唯一发生的事情是SSR端的onClick事件不会响应任何事情


0
投票

服务器端:

ReactDOM.hydrate

客户端:

var React = require("react"); var ReactDOMServer = require("react-dom/server"); var DefaultLayout = require("./layout/default"); var LikeButton = require("./LikeButton"); var IndexComponent = React.createClass({ render: function() { return ( <DefaultLayout title={this.props.name}> <div> <h1>React Test</h1> </div> <div id="testButton"> {ReactDOMServer.renderToString(<LikeButton />)} </div> <script type="text/babel" src="/js/react.js"></script> </DefaultLayout> ); } }); module.exports = IndexComponent;

点赞按钮:

var React = require("react"); var ReactDOM = require("react-dom"); var LikeButton = require("./LikeButton"); ReactDOM.hydrate( <LikeButton />, document.getElementById('testButton') );

	
© www.soinside.com 2019 - 2024. All rights reserved.