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;