如何在Isomorphic应用程序中将状态从DOM同步到我的React组件?

时间:2014-12-15 22:22:30

标签: reactjs isomorphic-javascript

我的问题

我正在React中构建一个同构应用程序,它首先呈现组件服务器端,然后利用React的智能重新呈现浏览器端。

我遇到过这种情况,在React能够首先呈现浏览器端之前,DOM可能与React组件的状态不同步。这可能发生在用户使用慢速Internet连接时,react.js文件需要一段时间才能下载(这也是我构建同构应用程序的原因) < / p>

实施例

以下是我放在一起展示这种情况的示例:http://jsfiddle.net/jesstelford/z4o44esb

  • 运行此示例
  • 勾选复选框
  • 点击&#34;渲染反应&#34;
  • 当前的React状态在控制台中输出
  • 请注意,它仍然设置为{done:false},这是不正确的
var TodoItem = React.createClass({

  // ...

  render: function() {
    return (
      <label>
        <input type="checkbox" defaultChecked={this.state.done} onChange={this.onChange} />
        {this.props.name}
      </label>
    );
  }
});

// User toggles checkbox ON here, before React is rendered browser-side

// render using React browser-side
var renderedComponent = React.render(component, document.getElementById('content'));

// Incorrectly outputs { done: false }  
console.log('React state:', renderedComponent.state);

可能的(一半)解决方案

我找到了一个使用React refs的可能解决方案:http://jsfiddle.net/jesstelford/z4o44esb/2

var TodoItem = React.createClass({

  // ...

  syncStateFromDOM: function() {
    this.setDone(this.refs.done.getDOMNode().checked);
  },

  render: function() {
    return (
      <label>
        <input ref="done" type="checkbox" defaultChecked={this.state.done} onChange={this.onChange} />
        {this.props.name}
      </label>
    );
  }
});

// User toggles checkbox ON here, before React is rendered browser-side

// render using React browser-side
var renderedComponent = React.render(component, document.getElementById('content'));

// Sync state from the DOM
renderedComponent.syncStateFromDOM()

// Correctly outputs { done: true }  
console.log('React state:', renderedComponent.state);

这种方法的缺点是:

  • 在呈现DOM
  • 之后,状态会同步
  • 需要在组件本身外部使用额外代码才能在首次渲染时进行同步

我的问题

在预渲染React组件服务器端时,是否有任何方法可以在呈现浏览器端之前将DOM状态同步到该React组件,因为在React加载到浏览器端之前用户操纵了DOM ?

谢谢!

1 个答案:

答案 0 :(得分:6)

这是一个有趣的问题!从较高的层面来看,问题在于React并没有抓住这一变化。单击复选框时冒泡到顶级组件的事件,因为它尚未在客户端实例化。您的半解决方案通过手动模拟对onChange的调用来处理此问题。我开始认为你可能需要排队onChange事件......但后来我意识到React已经拥有你需要的一切。

&#34;四分之三&#34;解决方案是简单地将syncStateFromDOM重命名为componentDidMount,甚至不用手动调用它。根据文档,在最新版本的React中,componentDidMount仅在浏览器中调用,并且它是组件安装后的生命周期回调(即React.render即将返回时)。它是您用例的理想之选。请参阅:http://jsfiddle.net/qdt4z3w9/

这解决了组件本身外部代码的问题!但是在原始渲染发生之后仍然存在状态设置。不幸的是,我认为这基本上就是React的工作方式 - 为了能够将现有的DOM节点与refs相匹配,每个组件都需要首先完全安装。但是额外的虚拟DOM差异是一个很小的代价,因为它的设计是闪电般的。

希望这有帮助!