Seth Duncan
Seth Duncan

Reputation: 1300

React Router ScrollToTop not working with Material UI

I'm using Material UI for a fairly simple website but I'm having trouble with ScrollToTop. I've followed the documentation but can't seem to find the issue with my code. The desired functionality is every time a link is clicked, the page loads at the top. Instead, when clicked, the page changes but is rendered in the same position as the previous. See below - I've simplified the code so you aren't blasted with a wall of text.

Documentation referenced: https://reacttraining.com/react-router/web/guides/scroll-restoration

Root Component

const homePage = () => (<Home />);
const helpPage = () => (<Help />);
const termsPage = () => (<Markdown>{terms}</Markdown>);
const privacyPage = () => (<Markdown>{privacy}</Markdown>);

class Header extends React.Component {

  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0);
    }
  }

  render() {
    return (
      <MuiThemeProvider theme={darkTheme}>
        <div className={classes.root}>
          <AppBar position="absolute" className={classes.appBar}>
            <Toolbar>
              <Link className={classes.link} to="/"><Typography>Home</Typography></Link>
              <Link className={classes.link} to="/help"><Typography>Help</Typography></Link>
              <IconButton onClick={this.props.logOut} className={classes.headerIcon}>
                <AccountCircleIcon />
              </IconButton>
            </Toolbar>
          </AppBar>
          <main className={classes.content}>
            <div className={classes.toolbar} />
            <Route exact path="/" component={homePage} />
            <Route path="/help" component={helpPage} />
            <Route path="/terms" component={termsPage} />
            <Route path="/privacy" component={privacyPage} />
            <Footer />
          </main>
        </div>
      </MuiThemeProvider>
    );
  }
}

Upvotes: 0

Views: 1030

Answers (1)

Seth Duncan
Seth Duncan

Reputation: 1300

I discovered the root of the issue. The ScrollToTop function was referencing the window, but the content in question was being rendered in the main element under the Material UI Header. My solution was to reference the main element - problem solved. See below.

class Header extends React.Component {
  main = null;

  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      this.main.scrollTo(0, 0);
    }
  }

  render() {
    return (
      <MuiThemeProvider theme={darkTheme}>
        <div className={classes.root}>
          <AppBar position="absolute" className={classes.appBar}>
            <Toolbar>
              <Link className={classes.link} to="/"><Typography>Home</Typography></Link>
              <Link className={classes.link} to="/help"><Typography>Help</Typography></Link>
              <IconButton onClick={this.props.logOut} className={classes.headerIcon}>
                <AccountCircleIcon />
              </IconButton>
            </Toolbar>
          </AppBar>
          <main ref={(ref) => { this.main = ref; }} className={classes.content}>
            <div className={classes.toolbar} />
            <Route exact path="/" component={homePage} />
            <Route path="/help" component={helpPage} />
            <Route path="/terms" component={termsPage} />
            <Route path="/privacy" component={privacyPage} />
            <Footer />
          </main>
        </div>
      </MuiThemeProvider>
    );
  }
}

----Edits---- Using React.createRef() as suggested by Pier

class Header extends React.Component {
 constructor(props) {
    super(props);
    this.main = null;
    this.setMainRef = (element) => {
      this.main = element;
    };
  }

  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      this.main.scrollTo(0, 0);
    }
  }

  render() {
    return (
      <MuiThemeProvider theme={darkTheme}>
        <div className={classes.root}>
          <AppBar position="absolute" className={classes.appBar}>
            <Toolbar>
              <Link className={classes.link} to="/"><Typography>Home</Typography></Link>
              <Link className={classes.link} to="/help"><Typography>Help</Typography></Link>
              <IconButton onClick={this.props.logOut} className={classes.headerIcon}>
                <AccountCircleIcon />
              </IconButton>
            </Toolbar>
          </AppBar>
          <main ref={this.setMainRef} className={classes.content}>
            <div className={classes.toolbar} />
            <Route exact path="/" component={homePage} />
            <Route path="/help" component={helpPage} />
            <Route path="/terms" component={termsPage} />
            <Route path="/privacy" component={privacyPage} />
            <Footer />
          </main>
        </div>
      </MuiThemeProvider>
    );
  }
}

Upvotes: 1

Related Questions