我正在使用标签渲染SVG组件。这些标签组件需要根据文本内容(以及它们的大小)正确布局,以避免重叠。
要获得每个标签的真实大小,每次更新标签内容时都需要双重渲染。
在标签组件级别,我需要
然后,在每次重绘时:
到目前为止,这是我实现标签组件的方式:
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
// ...
}
});
所以,我的问题不是关于算法,而是如果有更好的符合React的方法来实现它。使用状态缓存这种缓慢的计算'还是以React方式允许的DOM访问?双重渲染是React的一个不寻常的案例吗?
答案 0 :(得分:7)
我个人的观点是,你应该把所有重要的状态都放到一个组件的状态中。所以,是的,你建议的方式是正确的方法。
据我所知,双重渲染是将块大小作为状态的唯一方法,因为需要首先绘制块。由于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"/>;
}
});
在FooComponent中,您将自动获取boundingClientRect作为状态。如果你在不止一个地方使用getBBox(),我会实现类似的东西。