In ReactJS, I am facing an issue while trying to manipulate the DOM in the componentDidMount() method. The problem lies in the fact that the DOM is not fully rendered at this point, requiring me to use a setTimeout function, which I find undesirable.
Upon logging the scrollHeight of the rendered element in componentDidMount(), I noticed that it returns a different value compared to when I introduce a delay of let's say 100 milliseconds.
My objective is to automatically scroll down to the bottom of an element as discussed in this resource How to scroll to bottom in react?
The component in question is a modal window that displays the children of another component using {this.props.children}
. Initially, the modal window is set with visibility: hidden
and opacity: 0
, matching the height of the window when first appearing on the page. Upon clicking a button, it becomes visible but retains the initial window height until a few milliseconds have passed.
I suspect there may be an error in my implementation as the use of setTimeout indicates, although I have not yet identified it.
I also attempted to make DOM changes in the componentDidUpdate() method without success.
This is the code snippet from the modal-window component:
componentDidMount() {
console.log(document.querySelector('.myModal').scrollHeight);
setTimeout(function() {
console.log(document.querySelector('.myModal').scrollHeight);
}, 100);
}
The first console.log output shows, for example, 497, whereas the second one reveals approximately 952.
Update
In my modal-window component, I render a child component like so, such as for my inbox-thread:
<Modal>
<InboxThread />
</Modal>
The issue was resolved by waiting for the modal-window component to render its children, achieved by adjusting the Modal.js file as follows:
render() {
return (
<React.Fragment>
{this.props.children}
</React.Fragment>
);
}
Ultimately, I managed to solve the problem by passing a method through props from the parent component where I called the modal to check componentDidUpdate() in Modal.js.
The code now appears as follows in the parent component:
...
export default class InboxThreadList extends React.Component {
constructor(props) {
super(props);
this.scrollToModalBottom = this.scrollToModalBottom.bind(this);
}
render() {
return (
<React.Fragment>
...
<Modal onRender={this.scrollToModalBottom}>
<InboxThread/>
</Modal>
</React.Fragment>
)
}
scrollToModalBottom() {
const myModalObject = document.querySelector('.myModal');
myModalObject.scrollTop = myModalObject.scrollHeight;
}
}
And in the Modal.js file:
...
export default class Modal extends React.Component {
...
componentDidUpdate() {
if ('onRender' in this.props) {
this.props.onRender();
}
}
render() {
return (
<div className={'myModal'}>
{this.props.children}
</div>
);
}
I acknowledge the need to transition to using refs instead of document.querySelector, which can be implemented according to this guidance React - Passing ref from dumb component(child) to smart component(parent).