我有一个应用程序,我需要动态设置一个元素的高度(让我们说“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;

当前回答

实际上,有一个比使用request animationframe或timeout更简单、更清晰的版本。我很惊讶居然没人提起这件事: vanilla-js的onload处理程序。 如果可以,使用component did mount,如果不行,只需在jsx组件的onload处理程序上绑定一个函数。如果你想让函数运行每次渲染,也要在返回渲染函数的结果之前执行它。代码看起来是这样的:

runAfterRender = () => { const myElem = document.getElementById("myElem") 如果(myElem) { //做重要的事情 } } 呈现() { this.runAfterRender () 回报( < div onLoad = {this.runAfterRender} > / /更多的东西 < / div > ) }

}

其他回答

ReactDOM.render()文档:

如果提供了可选的回调,它将在 组件被呈现或更新。

React在这些情况下有一些生命周期方法,列表包括但不限于getInitialState, getDefaultProps, componentWillMount, componentDidMount等。

在你的情况和需要与DOM元素交互的情况下,你需要等待直到DOM准备好,所以使用componentDidMount如下:

/** @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({
  componentDidMount: function() {
    ReactDOM.findDOMNode(this).height = /* whatever HEIGHT */;
  },
  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;

此外,有关react生命周期的更多信息,您可以查看下面的链接: https://facebook.github.io/react/docs/state-and-lifecycle.html

实际上,有一个比使用request animationframe或timeout更简单、更清晰的版本。我很惊讶居然没人提起这件事: vanilla-js的onload处理程序。 如果可以,使用component did mount,如果不行,只需在jsx组件的onload处理程序上绑定一个函数。如果你想让函数运行每次渲染,也要在返回渲染函数的结果之前执行它。代码看起来是这样的:

runAfterRender = () => { const myElem = document.getElementById("myElem") 如果(myElem) { //做重要的事情 } } 呈现() { this.runAfterRender () 回报( < div onLoad = {this.runAfterRender} > / /更多的东西 < / div > ) }

}

对我来说,没有组合窗。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);
        }
    }());
}

对于功能性组件,您可以react-use-call-onnext-render,它是一个自定义钩子,允许在以后的渲染上安排回调。

在我的另一个项目中成功地使用了它。

如果需要dom元素的维度, 请看这个例子,它是react-use-call-onnext-render例子的第三个例子:

假设我们想要获取一个可移动DOM元素的尺寸,假设是由showBox状态控制的div 变量。为此,我们可以使用getBoundingClientRect()。但是,我们希望只在元素之后调用这个函数 挂载到dom中,因此将调度此调用在负责显示此元素的变量之后渲染一次 在dom中已经改变了,这个变量是showBox,所以他将是useCallOnNextRender的依赖:

const YourComponent = () => {
    const [showBox, setShowBox] = useState(false)
    const divRef = useRef()
    const callOnNextShowBoxChange = useCallOnNextRender()
    return (
        <>
            <div style={canvasStyle} id="canvas">
                <button style={boxStyle} onClick={() => {
                    setShowBox(!showBox)
                    callOnNextShowBoxChange(() => console.log(divRef.current.getBoundingClientRect())) //right value
                }}>toggle show box
                </button>
                <div style={{border: "black solid 1px"}} ref={divRef}>
                    {showBox ? <div style={boxStyle}>box2</div> : null}
                </div>
            </div>
        </>
    );
};