javascript - React, Using Refs to scrollIntoView() doesn't work in componentDidUpdate() - Stack Overflow

admin2025-02-23  6

I'm using Redux in my app, inside a Component I want to scroll to an specific div tag when a change in the store happens. I have the Redux part working so it triggers the ponentDidUpdate() method (I routed to this poennt view already). The problem as far as I can tell, is that the method scrollIntoView() doesn't work properly cos ponentDidUpdate() has a default behavior that scrolls to the top overwriting the scrollIntoView(). To work-around it I wrapped the function calling scrollIntoView() in a setTimeout to ensure that happens afeterwards. What I would like to do is to call a preventDefault() or any other more elegant solution but I can't find where to get the event triggering the 'scrollTop' I looked through the Doc here: .html#ponentdidupdate and the params passed in this function are ponentDidUpdate(prevProps, prevState) ,since there is no event I don't know how to call preventDefault()

I've followd this Docs: .html And tried different approaches people suggested here: How can I scroll a div to be visible in ReactJS?

Nothing worked though Here is my code if anyone has any tip for me, thanks

class PhotoContainer extends React.Component {

  ponentDidUpdate(){
    setTimeout(() => {
     this.focusDiv();
    }, 500);

  }
  focusDiv(){
    var scrolling = this.theDiv;
    scrolling.scrollIntoView();

  }

  render() {
    const totalList = [];
    for(let i = 0; i < 300; i += 1) {
        totalList.push(
            <div key={i}>{`hello ${i}`}</div>
        );
    }

  return (
      <div >
          {totalList}
          <div ref={(el) => this.theDiv = el}>this is the div I'm trying to scroll to</div>
      </div>
  )

}; }

I'm using Redux in my app, inside a Component I want to scroll to an specific div tag when a change in the store happens. I have the Redux part working so it triggers the ponentDidUpdate() method (I routed to this poennt view already). The problem as far as I can tell, is that the method scrollIntoView() doesn't work properly cos ponentDidUpdate() has a default behavior that scrolls to the top overwriting the scrollIntoView(). To work-around it I wrapped the function calling scrollIntoView() in a setTimeout to ensure that happens afeterwards. What I would like to do is to call a preventDefault() or any other more elegant solution but I can't find where to get the event triggering the 'scrollTop' I looked through the Doc here: https://facebook.github.io/react/docs/react-ponent.html#ponentdidupdate and the params passed in this function are ponentDidUpdate(prevProps, prevState) ,since there is no event I don't know how to call preventDefault()

I've followd this Docs: https://facebook.github.io/react/docs/refs-and-the-dom.html And tried different approaches people suggested here: How can I scroll a div to be visible in ReactJS?

Nothing worked though Here is my code if anyone has any tip for me, thanks

class PhotoContainer extends React.Component {

  ponentDidUpdate(){
    setTimeout(() => {
     this.focusDiv();
    }, 500);

  }
  focusDiv(){
    var scrolling = this.theDiv;
    scrolling.scrollIntoView();

  }

  render() {
    const totalList = [];
    for(let i = 0; i < 300; i += 1) {
        totalList.push(
            <div key={i}>{`hello ${i}`}</div>
        );
    }

  return (
      <div >
          {totalList}
          <div ref={(el) => this.theDiv = el}>this is the div I'm trying to scroll to</div>
      </div>
  )

}; }

Share Improve this question edited Nov 3, 2022 at 17:31 Jamal 8485 silver badges16 bronze badges asked Jul 13, 2017 at 9:45 RamiroIsBackRamiroIsBack 2701 gold badge4 silver badges15 bronze badges 6
  • 1 Are you sure scrollIntoView is supported on the browser version you are using? developer.mozilla/en/docs/Web/API/Element/… – Finbarr O'B Commented Jul 13, 2017 at 10:24
  • 1 Also, it may help to check if 'input' is truthy in your ref callback, remember the ref is called with the element on mount and null on unmount (facebook.github.io/react/docs/refs-and-the-dom.html) – Finbarr O'B Commented Jul 13, 2017 at 10:26
  • Yes, I'm using Chrome Version 59.0.3071.115 (Official Build) (64-bit) and it says 29, I guess that if it's greater that that it's supported. At first I was tempted to use element.scrollIntoView({block: "start", behavior: "smooth"}) but read not many browser supported parameters yet so I sticked to basic support. I also tryed boolean parameter (true and false) just in case but doen't help thanks for the hint @Finbarr O'B – RamiroIsBack Commented Jul 13, 2017 at 11:04
  • 2 The simplest truthy check is to do if(input){ this.textInput = input; }, but I suspect this isn't your problem. I've just tried to run your code, and it appears to work in my case. I had to include ponentDidMount() however as I was not manipulating state anywhere in my ponent (ponentDidUpdate() is only called if the ponent state is changed). I also removed the bootstrap CSS classes. See here: github./finbarrobrien/reacty/blob/master/src/App.js – Finbarr O'B Commented Jul 13, 2017 at 11:30
  • I just cloned your github 'reacty' and works fine also on my end, I just tried removing the bootstrap CSS classes as you did but still not working, now that I know it works on this simpler version , i'm gonna work on simplifying the code to make it work and start there , thanks i'll keep you posted – RamiroIsBack Commented Jul 13, 2017 at 11:56
 |  Show 1 more ment

2 Answers 2

Reset to default 5

Ok it's been a while but I got it working in another project without the setTimeOut function so I wanted to answer this question. Since Redux pass the new updates through props, I used the ponentWillRecieveProps() method instead of ponentDidUpdate() , this allowes you a better control over the updated properties and works as expected with the scrollIntoView() function.

class PhotoContainer extends React.Component {

  ponentWillReceiveProps(newProps) {
    if (
      this.props.navigation.sectionSelected !==
        newProps.navigation.sectionSelected &&
      newProps.navigation.sectionSelected !== ""
    ) {
      this.focusDiv(newProps.navigation.sectionSelected);
    }
  }

  focusDiv(section){
    var scrolling = this[section]; //section would be 'theDiv' in this example
    scrolling.scrollIntoView({ block: "start", behavior: "smooth" });//corrected typo
  }

  render() {
    const totalList = [];
    for(let i = 0; i < 300; i += 1) {
        totalList.push(
            <div key={i}>{`hello ${i}`}</div>
        );
    }

    return (
      <div >
          {totalList}
          <div ref={(el) => this.theDiv = el}>
            this is the div I am trying to scroll to
          </div>
       </div>
         )
      };
    }

I also struggled with scrolling to the bottom of a list in react that's responding to a change in a redux store and I happened upon this and a few other stackoverflow articles related to scrolling. In case you also land on this question as well there are a few ways this could be a problem. My scenario was that I wanted a 'loading' spinner screen while the list was rendering. Here are a few wrong ways to do this:

  1. When loading = true, render spinner, otherwise render list.
{loading ? 
   <Spinner />
:
   <List />
}

as stated above this doesn't work because the list you might want to scroll to the bottom of isn't rendered yet.

  1. When loading set the display to block for the spinner and none for the list. When done loading, reverse the display.
<div style={{display: loading ? 'block' : 'none'>
   <Spinner />
</div>
<div style={{display: loading ? 'none' : 'block'>
   <List />
</div>

This doesn't work either since the list you want to scroll to the bottom of isn't actually being displayed likely when you call the scroll.

The better approach for the above scenario is to use a loading that acts as an overlay to the ponent. This way both the spinner and list are rendered and displayed, the scroll happens, and when the loading is plete, the spinner can be de-rendered or set to be invisible.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1740302819a128719.html

最新回复(0)