有些JQuery插件不仅仅是为DOM节点添加行为,而是更改它们。例如,Bootstrap Switch转为
<input type="checkbox" name="my-checkbox" checked>
类似
<div class="bootstrap-switch bootstrap-switch-wrapper bootstrap-switch-on bootstrap-switch-large bootstrap-switch-animate">
<div class="bootstrap-switch-container">
<span class="bootstrap-switch-handle-on bootstrap-switch-primary">ON</span>
<label class="bootstrap-switch-label"> </label>
<span class="bootstrap-switch-handle-off bootstrap-switch-default">OFF</span>
<input type="checkbox" name="download-version" checked="" data-size="large" data-on-text="3" data-off-text="2.0.1">
</div>
</div>
与
$("[name='my-checkbox']").bootstrapSwitch();
与React并不相符:
Uncaught Error: Invariant Violation: findComponentRoot(..., .0): Unable to find
element. This probably means the DOM was unexpectedly mutated (e.g., by the
browser), usually due to forgetting a <tbody> when using tables or nesting <p> or
<a> tags. ...<omitted>...`.
是否有推荐的技术将这些插件合并到React组件中?或者它们是否从根本上打破了React的假设并且无法使用它?
答案 0 :(得分:58)
不,反应会对任何在反应之外修改其自身组件dom结构的事情做出反应(哈哈)。这是你不想做的事情。建议的解决方案是复制您尝试使用jquery或类似插件进行反应的功能。
话虽如此,对于特定情况,有一种合理的方法可以做到这一点,你不能没有它,但它本质上意味着包装一些无反应的dom内部反应。
示例:
var Example = React.createClass({
componentDidMount: function() {
var $checkboxContainer = $(this.refs.checkboxContainer.getDOMNode());
var $checkbox = $('<input />').prop('type', 'checkbox');
$checkboxContainer.append($checkbox);
$checkbox.bootstrapSwitch({});
},
render: function() {
return (
<div>
<div ref="checkboxContainer"></div>
</div>
)
}
});
现在,您正在使用嵌套div渲染组件。嵌套div第一次安装到dom时,嵌套div将获得一个jquery附加的复选框,然后它将在其上执行我们的jquery插件。
这个特定的示例组件没有什么意义,但是你可以看到它如何集成到一个更复杂的组件中,同时仍然允许你重新渲染和响应状态变化等。你只是失去了直接对...做出反应的能力事件/修改问题中的内容,就反应而言,不存在。
现在有了上面的例子,如果你有一些反应逻辑来添加/删除嵌套div,你必须在插入的div周围有相同的逻辑负责重新插入复选框并重新初始化它与jquery插件。但是因为react只在需要时修改了dom,所以这个插入的dom内容不会被删除,除非你做了一些修改容器div的方法,导致它被删除/重新渲染到dom。这意味着您仍然可以访问该容器div等的响应中的所有事件。
您还可以使用componentDidMount
函数进行响应,将事件或回调绑定到复选框本身的特定交互。只需确保在componentWillUnmount
中正确解除绑定,或者在特定情况下在组件生命周期中将其取消绑定。
答案 1 :(得分:21)
在这个精彩的ryanflorence教程中,您将了解如何执行此操作:
Wrapping DOM Libs
方法
- DOM libs通常操纵DOM
- React尝试重新渲染并查找 一个与上次不同的DOM并且吓坏了
- 我们隐藏了DOM 通过打破渲染树然后从React进行操作 重新连接lib操作的DOM。
- 我们的消费者 组件可以留在React-land。
醇>
答案 2 :(得分:8)
当然,有这样一种技术。我们一直在做这些事情。
render()
内,您返回空<div ref="placeholder" />
componentWillUnmount
中,您要清理它。调用&#39; destroy&#39;或其他任何需要避免内存泄漏的内容。那就是它。幸运的是,在React中以这种方式修改DOM是完全安全的。
如果你想让这个插件对道具变化作出反应,事情会变得有点棘手。您需要覆盖其他生命周期方法,例如componentWillReceiveProps
,检查道具实际更改的时间,并调用相应的插件方法。我可以更详细地解释一下,如果你有具体的问题,整个主题对于评论来说过于宽泛。
答案 3 :(得分:2)
这更像是一个哲学问题
创建React是为了优化DOM操作,并且当组件的状态通过setState更改时,在幕后有大量的连接方法
这样做会导致所述布线遍历其虚拟DOM以找到需要更新的节点
如果你必须使用React,是否试图保持编码的一致性,最好的办法就是在componentDidMount中应用JQuery DOM操作,如此...
componentDidMount(){
this.node = $("#"+this.props.id); // Keep a reference to the node
this.chart = this.node.easyPieChart(); // Apply JQuery transformation and keep a reference
this.percentTitle = this.chart.find(".percent"); // Keep a reference to the title
}
这样做之后,无论你的“刷新”方法是什么,都不要调用setState,而是调用你的JQuery组件可能有的任何更新方法,如此...
componentWillMount(){
this.interval = setInterval(this._doRefresh.bind(this), 1500);
}
_doRefresh( percentage ){
// Note how setState is NOT being called here
percentage = percentage || Math.floor (Math.random() * 100) // simulate since we're not getting it yet
this.chart.data('easyPieChart').update(percentage); // call easyPieChart's update
this.percentTitle.text(percentage);
}
此时,如果你问为什么要使用React,在我的情况下,这个组件是其他React组件列表中的一个项目,用于保持整个应用程序的一致性......你可以有类似的困境
如果,与我不同,你不幸的是你的组件没有更新方法,而且你不能制作一个,那么可能是重新考虑这种方法的时候了