[英]Refs in mount/update component lifecycle
我有一个无限的滚动列表,可以双向滚动。 该列表显示了每行5个项目的网格,该网格代表一周7天中的5个工作日。 斑马按天剥离斑马纹(甚至几个月的颜色略深)。 我想将月份标题放置在网格左侧的一列中,从该月的第一天开始,或者该月可用的最早的一天(考虑到数据中的AJAX,但并不总是从第一个工作日开始)的月份)。
我拥有所有必要的逻辑来确定哪一天是第一天(因为我只显示工作日,如果第一天是周末,那么月初可能不是第一天)。
到目前为止,我有以下内容:
ref
中的格式YYYYMM_start
或YYYYMM_end
。 然后,我使用具有与monthStamp
相同格式的YYYYMM
以及一个findMonthNode
(使用正则表达式)来接收在父组件上查找开始和结束节点的函数来呈现MonthTitle
组件。
然后,在MonthTitle
组件的componentDidMount
,可以将标题绝对相对于该月的起始节点定位。 我还调用了componentDidUpdate
完全相同的函数。
我的问题是,当我向后滚动列表时(请记住,在两个方向上都可以无限滚动):我的AJAX会触发并加载带有新月份标题的新图块,并且新月份标题会适当地呈现,但是是原始的第一个标题不会相应更新。 一些闲逛之后,我意识到, this.refs
在父组件componentDidUpdate
不等于 this.refs
在父组件componentDidMount
。 componentDidMount
似乎具有完整的列表,而componentDidUpdate
仅具有在挂载新节点(来自AJAX响应)之前存在的节点的列表。
由于componentDidUpdate
并没有所有新的引用,因此我无法相应地放置先前的第一个月标题,并且它仍然停留在componentDidMount
中最初呈现的位置(鉴于新数据)现在是不正确的位置。
为什么this.refs
在这两个函数( componentDidMount
和componentDidUpdate
)中this.refs
不同? 在安装和更新组件时,如何确保可以访问完整的this.refs
?
使用react 0.13.3
FYI
如果您在此处查看组件生命周期规格,您将看到每次更新componentDidUpdate
都会运行componentDidUpdate(通过组件或其祖先之一中的this.setState
),而不是在初始渲染之后运行:
componentDidUpdate(object prevProps, object prevState)
组件的更新刷新到DOM后立即调用。 初始渲染不调用此方法。
另一方面, componentDidMount
在初始渲染后运行,但在通过setState
更新后不运行:
componentDidMount()
初始渲染发生后立即仅在客户端(而不是服务器)上调用一次。
因此,如果您更新状态(通过组件中的this.setState
)并重新呈现组件,并有可能添加具有ref
属性的新子元素,则这些子元素将不会在父componentDidMount
的componentDidMount
可见,而在componentDidUpdate
可见。
另一方面,如果您更新父组件并且更新呈现新的子组件,则这些子组件的componentDidMount
实际上会在父组件的componentDidUpdate
之前触发,因为父组件在所有新的子组件均已正确安装并正确渲染之前尚未完成更新。 它会像这样:
componentDidMount
执行(也许有些令人惊讶,但是直到所有子级都挂载后,父级才完成挂载,这是有道理的) componentDidMount
执行 setState
更新,其中添加了一些子级,并且某些子级上次渲染已存在 componentDidMount
和执行所有以前存在的子级的componentDidUpdate
componentDidUpdate
执行 这是JSFiddle演示的。
好的,我想出了一个解决方案。 我没有让MonthTitle
在其生命周期回调中处理自己的位置( componentDidMount
和componentDidUpdate
),而是让其父级组件( Grid
)调用标题上的方法以将其放置在父级的componentDidUpdate
。
因此,大致而言,在Grid
,我具有以下内容:
componentDidUpdate() {
for (let [ref, component] of entries(this.refs)) {
if (/_title$/.test(ref)) {
var startOfMonthNode = React.findDOMNode(findRef("startOfMonth", this.refs, component.props.monthStamp))
var endOfMonthNode = React.findDOMNode(findRef("endOfMonth", this.refs, component.props.monthStamp))
component.position(startOfMonthNode, endOfMonthNode)
}
}
}
然后,在我的MonthTitle
组件中,定义定位逻辑:
position(startOfMonthNode, endOfMonthNode) {
React.findDOMNode(this).style["top"] = getDimension((startOfMonthNode || endOfMonthNode), "top") + window.scrollY - 116 + "px"
}
这意味着我必须将标题本身添加到Grid
refs
列表中。
因此,从概念上讲, 当位置更新从子组件的生命周期到父组件的生命周期发生变化时 ,差异就在转移。 由于父组件的componentDidUpdate
将在安装任何新的子组件后触发,因此我有完整的refs
列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.