Javascript 使用React.JS检索和缓存SVG节点边界框的最佳方法
我正在呈现一个带有标签的SVG组件。这些标签组件需要根据其文本内容(以及大小)正确布局,以避免重叠 要获得每个标签的真实大小,似乎每次更新标签内容时都需要双渲染 在标签组件级别,我需要Javascript 使用React.JS检索和缓存SVG节点边界框的最佳方法,javascript,svg,reactjs,Javascript,Svg,Reactjs,我正在呈现一个带有标签的SVG组件。这些标签组件需要根据其文本内容(以及大小)正确布局,以避免重叠 要获得每个标签的真实大小,似乎每次更新标签内容时都需要双渲染 在标签组件级别,我需要 第一次渲染它 检索真实SVG DOM节点的边界框 出于性能原因,缓存边界框 重新渲染组件以根据其缓存的边界框调整标签位置 然后,在每次重画时: 根据缓存的边界框进行渲染 比较以前和更新的道具之间的标签内容,如果更改: 更新并缓存标签边界框 根据更新和缓存的边界框重新渲染 到目前为止,我是如何实现我的标签组
- 第一次渲染它
- 检索真实SVG DOM节点的边界框
- 出于性能原因,缓存边界框
- 重新渲染组件以根据其缓存的边界框调整标签位置
- 根据缓存的边界框进行渲染
- 比较以前和更新的道具之间的标签内容,如果更改:
- 更新并缓存标签边界框
- 根据更新和缓存的边界框重新渲染
var Label = React.createClass({
updateBBox: function() {
// Trigger re-rendering
this.setState({
bbox: this.getDOMNode().getBBox()
});
},
componentDidMount: function() {
// Will trigger a re-rendering at mount
this.updateBBox();
},
componentDidUpdate: function(prevProps, prevState) {
// If content has changed, re-render
if (this.props.content !== prevProps.content) {
this.updateBBox();
}
},
render: function() {
// Render according to size from current bounding box if any cached
// ...
}
});
所以,我的问题不是关于算法,而是是否有更好的方法来实现这一点。使用状态缓存这种缓慢的“计算”或DOM访问是否以React方式允许?双重渲染对React来说是一种不寻常的情况吗?我个人的观点是,你应该把所有对你重要的状态都放到组件的状态中。所以,是的,你提出的方法是正确的 据我所知,双渲染是将块的大小作为状态获取的唯一方法,因为需要首先绘制块。因为React的性能非常好,所以这通常没有问题。如果是,则使用PureRenderMixin或其他检查子级中的shouldComponentUpdate以确保性能 但是请注意,将其作为mixin编写可能是明智的,因为“不要重复您自己” 我经常使用SVG,所以我经常需要块元素(SVG或html)的x、y宽度和高度 我写了一个叫做BoundingRectAware的小混音:
var shallowEqual = require('react/lib/shallowEqual');
// keep width and height of an element. You must make a "boundingRectTarget" ref
// to the element you would like to track
module.exports = {
getInitialState: function() {
return {rect: {
left: null, top: null, right: null, bottom: null, width: null, height: null
}};
},
componentDidMount: function() {
window.addEventListener("resize", this.updateDimensions);
this.updateDimensions();
},
componentWillUnmount: function() {
window.removeEventListener("resize", this.updateDimensions);
},
componentWillReceiveProps: function() {
this.updateDimensions();
},
updateDimensions: function() {
if (this.refs.boundingRectTarget) {
var rect = this.refs.boundingRectTarget.getDOMNode().getBoundingClientRect();
if (!shallowEqual(this.state.rect, rect)) {
this.setState({rect: rect});
}
}
}
};
可以这样使用:
var FooComponent = React.createClass({
mixins: [BoundingRectAware],
render: function() {
return <div className="foo-class" ref="boundingRectTarget"/>;
}
});
var FooComponent=React.createClass({
mixins:[BoundingRectAware],
render:function(){
返回;
}
});
在FooComponent中,您将自动获得BoundingClientAs状态。如果您在多个位置使用getBBox(),我会实现类似的功能。非常感谢您的详细回答。我希望在
组件diddupdate
中出现this.updateDimensions()
。为什么没有呢?此外,如果组件发生更改(例如,FooComponent.render
中的子项由于状态更新而不同),这是否正确地更新了边界矩形。在我的例子中,它似乎没有更新。如果您在componentDidMount
和componentdiddupdate
中使用实际的DOM元素,则可以从组件中挤出更多的性能。这样,就可以避免不必要地多次触发render
方法。当然,这需要通过refs
维护对给定元素的引用。