react:渲染后无法获得正确的元素宽度

IT技术 javascript iframe width reactjs
2021-05-03 05:04:58

如果一段文本大于其容器,我正在尝试在 React 中设置一个选取框,但我无法获得容器的正确宽度,即使在组件呈现之后也是如此。

我在另一个答案中读到React “after render” 代码?您必须使用我正在尝试的 requestAnimationFrame 但它仍然无法正常工作。

如果我记录容器的宽度,它会显示 147px 的宽度,这是在样式表中使用 min-width 设置的,但正确的宽度应该是 320px,当屏幕 min-width 为 600px 时,它是使用媒体查询设置的。

这是一个子组件,如果它有任何不同,父组件会在 iFrame 中呈现,并且 iFrame 的宽度远远超过 600px。

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> &ndash; <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;
  }
}

我尝试了许多不同的解决方案,包括layoutreact-component-width-mixin,但它们都不起作用。我尝试了 react component width mixin 因为在我的应用程序的另一部分我试图获取的值window.innerWidth但在渲染后也返回 0,除非我将超时设置为大约 2 秒,不幸的是有时 2 秒不够长由于数据加载和其他回调,所以这很容易刹车。

任何帮助都非常感谢。谢谢。

更新: 其中一个答案正确地指出我应该this.initMarquee();componentDidMount我正在做的内部调用,不幸的是我粘贴了错误的代码,因为我在测试时粘贴了错误的代码,以查看在内部调用它是否有所不同render正确的代码如下所示:

componentDidMount: function () {
  // Setup marquee
  this.initMarquee();
},

不幸的是,这也不起作用,我仍然收到不正确的 marqueeWrap 宽度。

更新:24/06/2015 只是为了澄清,这是我想要实现选取框效果,仅当文本大于其容器时,因为在文本不大时滚动它是毫无意义的。

这里还有一个来自 React 团队Github 问题的链接,它谈到了为什么 React 在浏览器绘制之前呈现。- 在这种情况下,我想知道如何可靠地获得相关元素的宽度。

3个回答

可能发生的一个问题是,当 componentDidMount 触发时,您的 CSS 尚未加载。这可能发生在 webpack 中,并且将 css 包含在你的包中,即使你已经在项目中的组件之前包含了 css。

正如您所指出的,在处理虚拟 DOM 时有几个问题。您绝对不想尝试使用 jQuery 来操作 DOM 节点,而 React 可能会因为您的尝试而对您大喊大叫。

有一个名为React-Context的库,它可以完全满足您的要求。您将其 api 公开给您的包装器组件,然后能够侦听虚拟 dom 内的组件上的事件。

这个库有点脏,但是它应该可以与您共享的代码示例一起使用。

您不应调用this.initMarquee();render() 方法。

通常,您根本不应该在render()方法中使用 DOM

尝试调用this.initMarquee();componentDidMount方法。

(我真的不明白requestAnimationFrame在这种情况下的用法