我有一个应用程序,我需要动态设置一个元素的高度(让我们说“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;
用ES6类代替React.createClass进行了一点更新
import React, { Component } from 'react';
class SomeComponent extends Component {
constructor(props) {
super(props);
// this code might be called when there is no element avaliable in `document` yet (eg. initial render)
}
componentDidMount() {
// this code will be always called when component is mounted in browser DOM ('after render')
}
render() {
return (
<div className="component">
Some Content
</div>
);
}
}
另外,检查React组件生命周期方法:组件生命周期
每个组件都有很多类似componentDidMount的方法。
componentWillUnmount() -组件即将从浏览器DOM中删除
对于功能性组件,您可以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>
</>
);
};
您可以更改状态,然后在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>
);
}
}
在我的经验窗口。requestAnimationFrame不足以确保DOM已经从componentDidMount完全渲染/ reflow-complete。我有代码运行,访问DOM后立即componentDidMount调用和使用单独的窗口。requestAnimationFrame将导致元素出现在DOM中;然而,对元素尺寸的更新还没有反映出来,因为回流还没有发生。
唯一真正可靠的方法是将我的方法包装在一个setTimeout和一个窗口中。requestAnimationFrame以确保React的当前调用堆栈在注册下一帧渲染之前被清除。
function onNextFrame(callback) {
setTimeout(function () {
requestAnimationFrame(callback)
})
}
如果我不得不推测为什么这是发生的/必要的,我可以看到React批处理DOM更新,直到当前堆栈完成后才实际应用更改到DOM。
最终,如果你在React回调后触发的代码中使用DOM度量,你可能会想要使用这个方法。