我有一个应用程序,我需要动态设置一个元素的高度(让我们说“app-content”)。它取应用程序的“chrome”的高度并减去它,然后设置“app-content”的高度以100%符合这些限制。这是超级简单的香草JS, jQuery,或骨干视图,但我努力弄清楚正确的过程将在React中这样做?

下面是一个示例组件。我想要能够设置应用内容的高度为窗口的100%减去动作栏和BalanceBar的大小,但我怎么知道什么时候所有的渲染和哪里我将把计算的东西在这个反应类?

/** @jsx React.DOM */
var List = require('../list');
var ActionBar = require('../action-bar');
var BalanceBar = require('../balance-bar');
var Sidebar = require('../sidebar');
var AppBase = React.createClass({
  render: function () {
    return (
      <div className="wrapper">
        <Sidebar />
        <div className="inner-wrapper">
          <ActionBar title="Title Here" />
          <BalanceBar balance={balance} />
          <div className="app-content">
            <List items={items} />
          </div>
        </div>
      </div>
    );
  }
});

module.exports = AppBase;

当前回答

您可以更改状态,然后在setState回调中进行计算。根据React文档,这是“保证在更新应用后触发”。

这应该在componentDidMount或代码中的其他地方完成(比如在调整大小事件处理程序上),而不是在构造函数中完成。

这是窗户的好替代品。它没有一些用户在这里提到的问题(需要结合setTimeout或多次调用它)。例如:

class AppBase extends React.Component {
    state = {
        showInProcess: false,
        size: null
    };

    componentDidMount() {
        this.setState({ showInProcess: true }, () => {
            this.setState({
                showInProcess: false,
                size: this.calculateSize()
            });
        });
    }

    render() {
        const appStyle = this.state.showInProcess ? { visibility: 'hidden' } : null;

        return (
            <div className="wrapper">
                ...
                <div className="app-content" style={appStyle}>
                    <List items={items} />
                </div>
                ...
            </div>
        );
    }
}

其他回答

我实际上遇到了类似行为的麻烦,我在一个组件中渲染了一个视频元素,它的id属性,所以当RenderDOM.render()结束时,它加载了一个需要id来找到占位符的插件,但它找不到它。

componentDidMount()中的setTimeout与0ms修复了它:)

componentDidMount() {
    if (this.props.onDidMount instanceof Function) {
        setTimeout(() => {
            this.props.onDidMount();
        }, 0);
    }
}

使用componentDidUpdate或componentDidMount的一个缺点是,它们实际上是在dom元素完成绘制之前执行的,而是在它们从React传递到浏览器的dom之后。

比如说,如果你需要set node。到呈现节点的scrollHeight。scrollTop,那么React的DOM元素可能不够。你需要等到元素被画完才能得到它们的高度。

解决方案:

使用requestAnimationFrame来确保你的代码在绘制新渲染的对象后运行

scrollElement: function() {
  // Store a 'this' ref, and
  var _this = this;
  // wait for a paint before running scrollHeight dependent code.
  window.requestAnimationFrame(function() {
    var node = _this.getDOMNode();
    if (node !== undefined) {
      node.scrollTop = node.scrollHeight;
    }
  });
},
componentDidMount: function() {
  this.scrollElement();
},
// and or
componentDidUpdate: function() {
  this.scrollElement();
},
// and or
render: function() {
  this.scrollElement()
  return [...]

对我来说,没有组合窗。requestAnimationFrame或setTimeout产生一致的结果。有时它会起作用,但并不总是如此——或者有时为时已晚。

我通过循环window来修复它。根据需要多次请求animationframe。 (一般为0 ~ 2 ~ 3次)

关键是diff > 0:在这里我们可以准确地确保页面何时更新。

// Ensure new image was loaded before scrolling
if (oldH > 0 && images.length > prevState.images.length) {
    (function scroll() {
        const newH = ref.scrollHeight;
        const diff = newH - oldH;

        if (diff > 0) {
            const newPos = top + diff;
            window.scrollTo(0, newPos);
        } else {
            window.requestAnimationFrame(scroll);
        }
    }());
}

在尝试了上面所有建议的解决方案后,没有运气,我发现我的一个元素在中间有CSS过渡,这就是为什么我不能得到正确的计算几何后道具改变。 所以我不得不使用onTransitionEnd监听器等待片刻,当尝试获得容器元素的DOM高度计算。 希望这能节省一些人的工作日,哈哈。

componentDidMount ()

此方法在呈现组件后调用一次。你的代码应该是这样的。

var AppBase = React.createClass({
  componentDidMount: function() {
    var $this = $(ReactDOM.findDOMNode(this));
    // set el height and width etc.
  },

  render: function () {
    return (
      <div className="wrapper">
        <Sidebar />
          <div className="inner-wrapper">
            <ActionBar title="Title Here" />
            <BalanceBar balance={balance} />
            <div className="app-content">
              <List items={items} />
          </div>
        </div>
      </div>
    );
  }
});