【问题标题】:How do I sync state from the DOM to my React Component in an Isomorphic Application?如何在同构应用程序中将状态从 DOM 同步到我的 React 组件?
【发布时间】:2015-02-14 03:38:44
【问题描述】:

我的问题

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

我遇到了一种情况,在 React 能够首先呈现浏览器端之前,DOM 可能与 React 组件的状态不同步。当用户的互联网连接速度较慢时,可能会发生这种情况,并且 react.js 文件需要一段时间才能下载(这也是我构建同构应用程序的原因)

示例

这是我整理的一个例子来展示这种情况:http://jsfiddle.net/jesstelford/z4o44esb

  • 运行此示例
  • 切换复选框
  • 点击“渲染反应”
  • 当前 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 组件时,有没有办法在 React 组件渲染浏览器端之前将 DOM 状态同步到该 React 组件,因为在浏览器端加载 React 之前用户已经操作了 DOM ?

谢谢!

【问题讨论】:

  • 您能否详细说明“用户更改了服务器端的状态”是什么意思?
  • 我没有在问题的任何地方这么说 - 还有其他短语可以为您澄清吗?
  • 啊,没有意识到你延迟渲染 React 的时间比 document#ready 长。很抱歉。

标签: reactjs isomorphic-javascript


【解决方案1】:

这是一个有趣的问题!在高层次上,问题是 React 没有捕捉到当您单击复选框时冒泡到顶级组件的“更改”事件,因为它还没有在客户端实例化。您的半解决方案通过手动模拟对onChange 的调用来处理此问题。我开始认为你可能需要排队 onChange 事件......但后来我意识到 React 已经拥有你需要的一切。

“四分之三”的解决方案是简单地将syncStateFromDOM 重命名为componentDidMount,甚至不用手动调用它。根据文档,在最新版本的 React 中,componentDidMount 仅在浏览器中调用,它是组件挂载后的生命周期回调(即当 React.render 即将返回时)。这是您的用例的理想场所。见:http://jsfiddle.net/qdt4z3w9/

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

希望这会有所帮助!

【讨论】:

  • 这是一个很棒的四分之三解决方案!看起来 100% 的解决方案将是一个介于 componentWillMountcomponentDidMount 之间的生命周期事件。现在,我将不接受它,以防出现另一个解决方案,让我们更接近 100%。谢谢!
猜你喜欢
  • 2023-01-22
  • 2020-05-22
  • 2020-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-02
相关资源
最近更新 更多