Dealing with scroll position when you insert content is usually a difficult problem to solve. We'll see how to use React life cycle methods to solve it elegantly.
Insertion at the bottom
The first example is to maintain the scroll position at the bottom when an element is inserted at the bottom. A common use case is a chat application.
In order to scroll at the bottom, we can do that on componentDidUpdate
. It happens every time the element is re-rendered.
componentDidUpdate: function() { var node = this.getDOMNode(); node.scrollTop = node.scrollHeight; }, |
But this is going to always scroll to the bottom, which can be very annoying if you want to read what was above. Instead you want to scroll only if the user was already at the bottom. To do that, we can check the scroll position before the component has updated with componentWillUpdate
and scroll if necessary at componentDidUpdate
componentWillUpdate: function() { var node = this.getDOMNode(); this.shouldScrollBottom = node.scrollTop + node.offsetHeight === node.scrollHeight; }, componentDidUpdate: function() { if (this.shouldScrollBottom) { var node = this.getDOMNode(); node.scrollTop = node.scrollHeight } }, |
Note: we use this.shouldScrollBottom = ...;
and not this.setState({shouldScrollBottom: ...});
because we don't want to trigger another render. We just need to manage that value between the two events.
Insertion at the top
The other use case is adding elements at the top of the page but doing so without screwing up the current scroll position of the user. An example is a log view where you can scroll to the top to read historical context.
This is using a similar technique. On componentWillUpdate
we store the scroll position and on componentDidUpdate
we scroll to the added delta.
componentWillUpdate: function() { var node = this.getDOMNode(); this.scrollHeight = node.scrollHeight; this.scrollTop = node.scrollTop; }, componentDidUpdate: function() { var node = this.getDOMNode(); node.scrollTop = this.scrollTop + (node.scrollHeight - this.scrollHeight); }, |
Conclusion
React has not been designed to handle scroll position natively. However, it provides escape hatches from the declarative paradigm in order to be able to implement them.