反应:scrollIntoView 仅在 setTimeout 中工作



我的应用程序由用户键入消息的基本输入组成。然后将消息附加到所有其他消息的底部,就像聊天一样。当我将新的聊天消息添加到消息数组时,我还想向下滚动到该消息。

每个html元素都有一个动态创建的ref,基于其在循环中的索引,将它们打印出来。添加新消息的代码尝试在添加最新消息后滚动到该消息。

仅当此代码放置在 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' });
};

如果我不将 scrollToLatest(( 的调用放在 setTimeout 中,它不起作用。它不会产生错误,它什么都不做。我的想法是它试图在状态完全设置之前运行,但我尝试向 setState 函数添加回调来运行它,但它也不起作用。

添加新的注释和 ref 将需要在组件更新生命周期中再次渲染,并且您正在尝试在渲染之前访问 ref(setTimeout 解决了这个问题(。你应该努力使用 React 组件生命周期方法。尝试在生命周期方法组件 DidUpdate 中调用 scrollToLate,该组件在执行渲染后调用。

虽然您肯定是正确的设置状态是一个异步过程,但更新生命周期方法(例如,shouldComponentUpdate、render 和 componentDidUpdate(直到状态更新后才会启动,并且您的 setState 回调可能会在组件实际更新之前被调用通过 render。 React 文档可以提供有关组件生命周期的一些额外说明。

最后,为了不在每个更新时调用滚动方法(仅在重要的更新上(,您可以实现另一种生命周期方法 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
}

最新更新