Next.js (React) & ScrollMagic

2019-04-20 03:58发布

问题:

I would like to implement an animation to fade sections, like in this example, into my application. Therefore I've had a look at fullPage.js.

However, since I need to integrate it into a Next.js React app with server-side rendering I can't use it since it relays on jQuery, which doesn't support SSR. Therefore I've tried my luck with ScrollMagic, which doesn't relay on jQuery. But it also doesn't support SSR (needs window), therefore I've initialized it in the componentDidMount() method and even loaded it there (like it's recommended here).

It currently works initially, but as soon as you change the page and an AJAX request is done and Next.js replaces the page, an error will be thrown (see below):

Node was not found

I've tried to destroy ScrollMagic before the AJAX request in componentWillUnmount(), but with no luck. I can't figure out what's wrong and unfortunately, I couldn't find any documentation about ScrollMagic with React or Next.js.

This is my entire component:

import React from 'react';
import PropTypes from 'prop-types';

class VerticalSlider extends React.Component {
  constructor(props) {
    super(props);
    this.ScrollMagic = null;
    this.controller = null;
    this.scenes = [];
    this.container = React.createRef();
  }

  componentDidMount() {
    if (this.container.current) {
      // Why "require" here?
      // https://github.com/zeit/next.js/issues/219#issuecomment-393939863
      // We can't render the component server-side, but we will still render
      // the HTML
      // eslint-disable-next-line global-require
      this.ScrollMagic = require('scrollmagic');
      this.initScroller();
    }
  }

  componentWillUnmount() {
    this.scenes.forEach(scene => {
      scene.destroy();
    });
    this.controller.destroy();
    this.scenes = [];
    this.controller = null;
  }

  initScroller() {
    try {
      this.controller = new this.ScrollMagic.Controller();
      if (this.container.current !== null && this.container.current.children) {
        [...this.container.current.children].forEach(children => {
          const scene = new this.ScrollMagic.Scene({
            triggerElement: children,
            duration: window.innerHeight * 1.5,
            triggerHook: 0,
            reverse: true
          });
          scene.setPin(children);
          this.scenes.push(scene);
        });
        this.controller.addScene(this.scenes);
      }
    } catch (e) {
      console.log(e);
    }
  }

  render() {
    return (
      <div ref={this.container}>
        {this.props.sections}
      </div>
    );
  }
}

VerticalSlider.propTypes = {
  sections: PropTypes.arrayOf(PropTypes.node).isRequired
};

export default VerticalSlider;

回答1:

This is probably not a good answer for SO but I thought maybe this would help.

React has a really good and well maintained transition library called react-transition-group and Next.js has a similar library called next-page-transitions. There is a good example showing how to use it. Example uses _app.js for easily animating every page transition. I suggest you to take a look at that example and try to integrate it into your application.