我的应用程序由用户输入消息的基本输入组成。然后,该消息将被附加到所有其他消息的底部,就像聊天一样。当我将新的聊天消息添加到消息数组时,我也想向下滚动到该消息。
每个html元素都有一个基于其在循环中的索引的动态创建的引用,该引用会将其打印出来。添加新消息的代码在添加后会尝试滚动到最新消息。
此代码仅在放置在setTimeout函数中时才有效。我不明白为什么会这样。
从其数组创建注释的代码
comments = this.state.item.notes.map((comment, i) => (
<div key={i} ref={i}>
<div className="comment-text">{comment.text}</div>
</div>
));
添加新评论的按钮
<input type="text" value={this.state.textInput} onChange={this.commentChange} />
<div className="submit-button" onClick={() => this.addComment()}>Submit</div>
添加评论功能
addComment = () => {
const value = this.state.textInput;
const comment = {
text: value,
ts: new Date(),
user: 'Test User',
};
const newComments = [...this.state.item.notes, comment];
const newState = { ...this.state.item, notes: newComments };
this.setState({ item: newState });
this.setState({ textInput: '' });
setTimeout(() => {
this.scrollToLatest();
}, 100);
}
scrollToLatest = () => {
const commentIndex = this.state.xrayModalData.notes.length - 1;
this.refs[commentIndex].scrollIntoView({ block: 'end', behavior: 'smooth' });
};
如果我没有在setTimeout内放置对scrollToLatest()的调用,它将无法正常工作。它不会产生错误,它什么都不做。我以为它是在状态完全设置之前尝试运行的,但是我尝试向setState函数添加回调以运行它,而且它也不起作用。
答案 0 :(得分:0)
添加新的评论和参考将require another render in the component update lifecycle,并且您试图在呈现参考之前访问它(setTimeout已解决,有点类似)。您应该努力使用React组件生命周期方法。尝试在生命周期方法componentDidUpdate内部调用您的scrollToLatest,该方法在渲染执行后调用。
虽然您可以肯定的是,设置状态是一个异步过程,但更新生命周期方法(例如,shouldComponentUpdate,render和componentDidUpdate)要等到状态更新后才启动,并且setState回调可能在调用之前该组件实际上是通过渲染更新的。 React docs可以提供有关组件生命周期的更多说明。
最后,为了不使每次更新都调用滚动方法(仅在重要的更新上),您可以实现另一个生命周期方法getSnapshotBeforeUpdate,该方法可以比较以前的状态和当前状态,并传递返回值值到componentDidUpdate。
getSnapshotBeforeUpdate(prevProps, prevState) {
// If relevant portion or prevState and state not equal return a
// value, else return null
}
componentDidUpdate(prevProps, prevState, snapshot) {
// Check value of snapshot. If null, do not call your scroll
// function
}