反应“渲染后”代码?

我有一个应用程序,需要动态设置元素的高度(让我们说“ app-content”)。它获取应用程序“ chrome”的高度,然后减去它的高度,然后将“ app-content”的高度设置为在这些约束内适合100%。这对于香草JS,jQuery或Backbone视图来说非常简单,但是我正在努力弄清楚在React中执行此操作的正确过程是什么?

下面是一个示例组件。我希望能够将app-content的高度设置为窗口的100%减去ActionBarand 的大小BalanceBar,但是如何知道何时呈现所有内容以及将计算内容放在此React类的什么位置?

/** @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;
飞云Tom小宇宙2020/03/10 09:23:32

当我需要打印接收大量数据并在画布上绘画的react组件时,我遇到了奇怪的情况。我已经尝试了所有提到的方法,但没有一种方法对我可靠地起作用,在setTimeout中使用requestAnimationFrame可以在20%的时间内获得空的画布,因此我做了以下工作:

nRequest = n => range(0,n).reduce(
(acc,val) => () => requestAnimationFrame(acc), () => requestAnimationFrame(this.save)
);

基本上,我做了一个requestAnimationFrame的链,不确定是否是个好主意,但是到目前为止对我来说这在100%的情况下都有效(我使用30作为n变量的值)。

米亚小小神乐2020/03/10 09:23:32

实际上,有比使用请求animationframe或timeout更简单,更简洁的版本。Iam对没有人提出来感到惊讶:vanilla-js onload处理程序。如果可以,请使用组件安装,否则,只需在jsx组件的onload处理程序上绑定一个函数。如果要让函数运行每个渲染,则在返回结果之前,还要执行它。代码如下所示:

runAfterRender = () => 
{
  const myElem = document.getElementById("myElem")
  if(myElem)
  {
    //do important stuff
  }
}

render()
{
  this.runAfterRender()
  return (
    <div
      onLoad = {this.runAfterRender}
    >
      //more stuff
    </div>
  )
}

}

路易Gil2020/03/10 09:23:32

ReactDOM.render()文档中:

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

逆天小胖Mandy2020/03/10 09:23:32

对我而言,没有任何结合window.requestAnimationFramesetTimeout产生一致的结果。有时它会奏效,但并非总是如此-有时会为时已晚。

我通过循环window.requestAnimationFrame多次来解决它
(通常为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);
        }
    }());
}
猿阿飞Tom2020/03/10 09:23:32

我实际上在遇到类似行为方面的麻烦,我在具有其id属性的Component中渲染了一个视频元素,因此当RenderDOM.render()结束时,它会加载一个需要ID来查找占位符的插件,但找不到它。

在componentDidMount()内部具有0ms的setTimeout修复了它:)

componentDidMount() {
    if (this.props.onDidMount instanceof Function) {
        setTimeout(() => {
            this.props.onDidMount();
        }, 0);
    }
}
西里Jim2020/03/10 09:23:32

我遇到了同样的问题。

在大多数情况下,使用hack-ish是可行setTimeout(() => { }, 0)componentDidMount()

但不是特殊情况;而且我不想使用,ReachDOM findDOMNode因为文档中说:

注意:findDOMNode是用于访问基础DOM节点的转义口。在大多数情况下,不建议使用此逃生阴影,因为它会穿透组件抽象。

(来源:findDOMNode

因此,在该特定组件中,我不得不使用该componentDidUpdate()事件,因此我的代码最终如下所示:

componentDidMount() {
    // feel this a little hacky? check this: http://stackoverflow.com/questions/26556436/react-after-render-code
    setTimeout(() => {
       window.addEventListener("resize", this.updateDimensions.bind(this));
       this.updateDimensions();
    }, 0);
}

接着:

componentDidUpdate() {
    this.updateDimensions();
}

最后,就我而言,我必须删除在中创建的侦听器componentDidMount

componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions.bind(this));
}
小胖Gil2020/03/10 09:23:32

我觉得这个解决方案很脏,但是我们开始:

componentDidMount() {
    this.componentDidUpdate()
}

componentDidUpdate() {
    // A whole lotta functions here, fired after every render.
}

现在,我将坐在这里等待投票否决。

TomNear前端2020/03/10 09:23:32

以我的经验window.requestAnimationFrame,还不足以确保DOM已从完全渲染/重排完整componentDidMount我运行的代码在componentDidMount调用后立即访问DOM,并且仅使用它window.requestAnimationFrame会导致DOM中存在该元素;但是,由于尚未发生回流,因此尚未反映出元素尺寸的更新。

唯一真正可靠的方法是将我的方法包装在setTimeout和中,window.requestAnimationFrame以确保在注册下一帧渲染之前清除React的当前调用堆栈。

function onNextFrame(callback) {
    setTimeout(function () {
        requestAnimationFrame(callback)
    })
}

如果我不得不猜测为什么会发生这种情况/有必要的话,我可以看到React批处理DOM更新,并且直到当前堆栈完成之后才真正将更改应用于DOM。

最终,如果您在代码中使用DOM度量,则需要在React回调之后触发,您可能需要使用此方法。

Jim理查德2020/03/10 09:23:32

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>
    );
  }
});