反应:渲染后无法获得正确的元素宽度
Posted
技术标签:
【中文标题】反应:渲染后无法获得正确的元素宽度【英文标题】:React: Can't get correct width of element after render 【发布时间】:2015-09-07 20:14:14 【问题描述】:如果一段文本大于其容器,我正在尝试在 React 中设置一个选取框,但我无法获得容器的正确宽度,即使在组件渲染之后也是如此。
我在另一个答案React “after render” code? 中读到,您必须使用我正在尝试的 requestAnimationFrame,但它仍然无法正常工作。
如果我记录容器的宽度,它会显示 147px 的宽度,这是在样式表中使用 min-width 设置的,但正确的宽度应该是 320px,当屏幕的 min-width 为 600px 时使用媒体查询设置。
这是一个子组件,如果有任何区别,父组件会在 iFrame 中呈现,并且 iFrame 的宽度远超过 600 像素。
JS:
module.exports = React.createClass(
componentDidUpdate: function ()
// Setup marquee
this.initMarquee();
,
render: function ()
// Setup marquee
this.initMarquee();
var artistName = this.props.artist.artistName;
var trackName = this.props.track.trackName;
return (
<div className="MV-player-trackData no-select" ref="mvpTrackData">
<div className="MV-player-trackData-marquee-wrap" ref="mvpMarqueeWrap">
<div className="MV-player-trackData-marquee" ref="mvpMarquee">
<a className="MV-player-trackData-link no-select" href=this.props.storeUrl target="_blank">
<span id="mvArtistName">artistName</span> – <span id="mvTrackName">trackName</span>
</a>
</div>
</div>
</div>
)
,
initMarquee: function ()
if ( typeof requestAnimationFrame !== 'undefined' )
//store a this ref, and
var self = this;
//wait for a paint to setup marquee
window.requestAnimationFrame(function()
self.marquee();
);
else
// Suport older browsers
window.setTimeout(this.marquee, 2000);
,
marquee: function ()
var marquee = React.findDOMNode(this.refs.mvpMarquee);
var marqueeWrap = React.findDOMNode(this.refs.mvpMarqueeWrap);
// If the marquee is greater than its container then animate it
if ( marquee.clientWidth > marqueeWrap.clientWidth )
marquee.className += ' is-animated';
else
marquee.className = marquee.className.replace('is-animated', '');
);
CSS:
.MV-player-trackData-marquee-wrap
height: 20px;
line-height: 20px;
min-width: 147px;
overflow: hidden;
position: relative;
width: 100%;
@media only screen and (min-width : 600px)
min-width: 320px;
我尝试了多种不同的解决方案,包括laidout 和react-component-width-mixin,但它们都不起作用。我尝试了反应组件宽度混合,因为在我的应用程序的另一部分中,我试图获取 window.innerWidth
的值,但渲染后它也返回 0,除非我将超时设置为大约 2 秒,但不幸的是,有时 2 秒不是由于数据加载和其他回调,时间不够长,因此很容易刹车。
非常感谢任何帮助。谢谢。
更新:
正确的答案之一指出我应该在componentDidMount
内调用this.initMarquee();
,我正在这样做,不幸的是,我在测试时粘贴了错误的代码,以查看在render
内调用它是否有所不同。正确的代码如下所示:
componentDidMount: function ()
// Setup marquee
this.initMarquee();
,
不幸的是,这也不起作用,我仍然收到错误的 marqueeWrap 宽度。
更新:2015 年 6 月 24 日 澄清一下,这是我想要实现的marquee effect,仅当文本大于其容器时,因为它不更大时滚动它是毫无意义的。
这里还有一个链接,指向来自 React 团队的 Github Issue,讲述了为什么 React 在浏览器绘制之前呈现。 - 既然如此,我想知道如何可靠地获取相关元素的宽度。
【问题讨论】:
我不是 100% 清楚你的目标是什么。你想防止你的内容溢出容器吗?你遇到了什么问题? 不,我希望我的内容在其大于其容器时自动在其容器内水平滚动,就像一个选框效果,类似于 jsfiddle.net/jonathansampson/xxuxd 【参考方案1】:一个可能发生的问题是,当 componentDidMount 触发时,您的 CSS 尚未加载。这可能发生在 webpack 中,并且在包含您的 js 的包中包含 css,即使您在项目中的组件之前包含 css。
【讨论】:
这是我的情况,我浪费了将近一天的时间试图找到可能导致此问题的原因,但从未想过在css
之后加载 js
,这是在 js 之前加载 css 的方法:@ 987654321@【参考方案2】:
正如您所指出的,在处理虚拟 DOM 时存在几个问题。您绝对不想尝试使用 jQuery 来操作 DOM 节点,而 React 可能会因为您的尝试而尖叫。
有一个名为React-Context 的库可以完全按照您的要求进行操作。你可以将它的 api 暴露给你的包装组件,然后就可以监听虚拟 dom 中组件上的事件。
这个库有点尘土飞扬,但它应该可以与您共享的代码示例一起使用。
【讨论】:
感谢@newswim 的更新。我不再积极研究这个了,但你的解决方案听起来很有趣!如果我重新开始工作,我将实施您的解决方案并在这里报告。谢谢【参考方案3】:你不应该在 render() 方法中调用this.initMarquee();
。
一般来说,您根本不应该在 render()
方法中使用 DOM。
尝试在componentDidMount
方法中调用this.initMarquee();
。
(我真的不明白requestAnimationFrame
在这种情况下的用法)
【讨论】:
感谢您发现@ByScripts - 你是对的,我已经这样设置了,不幸的是它没有工作。如链接答案中所述,使用 requestAnimationFrame 是因为:“使用 componentDidUpdate 或 componentDidMount 的一个缺点是它们实际上是在绘制 dom 元素之前执行的,但在它们从 React 传递到浏览器的 DOM 之后。 "以上是关于反应:渲染后无法获得正确的元素宽度的主要内容,如果未能解决你的问题,请参考以下文章