GSAP Animations(TweenMax) not triggering in React, - javascript

I cannot figure out for the life me what how to get this Gsap animations to work. I'm still learning react but I was able to get everything to work properly in a standard project using html, css, and javascipt but i wanted to try and recreate the effect in React. There's much more code, it'll compile but the animations are kicking in. The error on the console says nothing is wrong and VSCode says nothing is wrong so i'm at a loss. Seems like it should be a simple fix though.
function App() {
// Constants
const leftContainer = document.querySelector('.left-container');
if (leftContainer) {
gsap.from(".left-container", {
duration: 2,
width: '0',
ease: "power3.inOut",
});
}
return (
<>
<div className='containers'>
<div className="left-container">
</div>
</div>
</>
);
};
export default App;
However in a basic HTML it works when I write it as follows...
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
<script type="text/javascript">
TweenMax.from(".left-container", 2, {
width: "0",
ease: Expo.easeInOut
});
I also tried rewriting everything to follow the modern best practises.

In order to use gsap in react, make sure you have followed these steps:
Create and run basic react app.
npx create-react-app my-app
cd my-app
npm start
Install gsap in the react app using:
npm install gsap
Import the gsap module into the app and use it with the useEffect hook.
import React, { useEffect, useRef } from "react";
import gsap from "gsap";
import "./App.css";
function App() {
const appRef = useRef(); // create a ref for the root level element
useEffect(() => {
let ctx = gsap.context(() => {
// normal selector text, automatically scoped to appRef
gsap.from(".left-container", {
duration: 2,
width: 0,
ease: "power3.inOut",
});
}, appRef);
return () => ctx.revert();
});
return (
<>
<div className="containers" ref={appRef}>
<div className="left-container"></div>
</div>
</>
);
}
export default App;
Here, React will re-run the useEffect() on every render. If you want to avoid that, add empty dependency array.
Like this:
useEffect(() => {
// -- YOUR CODE --
}, []); // <- empty dependency array
Check this documentation for more info: greensock.com/react

Related

Working Vue 3 app empties mounted element when using Vue as an npm package

I'm working with a very simple Vue 3 app, listed below.
This works like a charm when including Vue as a script, see code snippet.
I need to use it with webpack however, and therefore include it as an npm package.
In this case the app loads, but Vue empties everything inside the div it's mounted on.
See CodeSandbox example
I've tried different ways to export and import the App object, but none work.
What am I overlooking?
const {ref} = Vue;
const App = {
setup() {
const count = ref(0);
const inc = () => {
count.value++;
};
return {count, inc};
}
}
Vue.createApp(App).mount('#simple-example')
<head>
<script src="https://unpkg.com/vue#3.2.29/dist/vue.global.prod.js"></script>
</head>
<body>
<div id="simple-example">
<h1>Hello Vue 3!</h1>
<button #click="inc">Clicked {{ count }} times.</button>
</div>
</body>
Changing this:
import { createApp } from "vue";
into this:
import { createApp } from "vue/dist/vue.esm-bundler";
fixed the problem. Thanks to Estus Flask
UPDATE
The fix can be further improved by creating an alias for vue in the webpack config file:
resolve: {
alias: {
vue: "vue/dist/vue.esm-bundler.js"
}
}
That will make it possible to use "vue" again in the import statement, which then points to the vue.esm-bundler.js instead of the default vue.runtime.es.js.

How to use vanta with nextjs?

I am trying to use vanta with next.js, following this guide. It works completely fine with the Net Effect, however, when I try to use the Globe Effect, I get
[VANTA] Init error TypeError: r.Geometry is not a constructor
at h.onInit (vanta.globe.min.js:1)
at h.init (vanta.globe.min.js:1)
at new r.VantaBase (vanta.globe.min.js:1)
at new h (vanta.globe.min.js:1)
at r.<computed> (vanta.globe.min.js:1)
I have isolated Vanta into an Background Component
//Background.js
import { useState, useRef, useEffect } from "react";
import NET from "vanta/dist/vanta.globe.min"
import * as THREE from "three";
export default function Background({ width, height, children }) {
const [vantaEffect, setVantaEffect] = useState(0);
const vantaRef = useRef(null);
useEffect(() => {
if (!vantaEffect) {
setVantaEffect(
NET({
THREE,
el: vantaRef.current,
})
);
}
return () => {
if (vantaEffect) vantaEffect.destroy();
};
}, [vantaEffect]);
return (
<div ref={vantaRef}>{children}</div>
)
}
And added the THREE script into my _app.js
import '../styles/globals.css'
import Head from "next/head";
import Navbar from "../components/Navbar";
import { useEffect } from "react";
export default function App({ Component, pageProps }) {
useEffect(() => {
const threeScript = document.createElement("script");
threeScript.setAttribute("id", "threeScript");
threeScript.setAttribute(
"src",
"https://cdnjs.cloudflare.com/ajax/libs/three.js/r121/three.min.js"
);
document.getElementsByTagName("head")[0].appendChild(threeScript);
return () => {
if (threeScript) {
threeScript.remove();
}
};
}, []);
return (
<>
<Head>
<title>BrainStorm Tutoring</title>
</Head>
<Navbar />
<Component {...pageProps} />
</>
)
}
and used it like so
//index
import Background from "../components/Background";
export default function Home() {
return (
<Background height="400" width="400">
<h1 className="text-white text-8xl text-left p-36">Fish Bowl</h1>
</Background >
)
}
Is it something wrong with THREE, or is it that next.js can't support vanta?
I have that issue with Halo, so i think the THREE object was not available or was not defined in the HALO.js file.
So i go to the official github repo of Vanta and take the source of Halo and Net (the tutorial effect) file, and i found constructor was missing in the Halo file. So i take the one of Net and put in the Halo file.
constructor(userOptions) {
THREE = userOptions.THREE || THREE;
super(userOptions);
}
Then i import my custom Halo file for the effect and it works.
I was playing around with this and found that, if I keep the Three.js version to 122. I don't get the error. Apparently any version after that has a breaking change.

window.Calendly.initInlineWidget is not defined on first load but works after refresh with useEffect in React and Gatsby

I am using Gatsby with React and am trying to implement a Calendly booking system. It sort of works. The issue is on first load it gives me the error
TypeError: Cannot read property 'initInlineWidget' of undefined
seen here
If I refresh the page the Calendly Object loads and renders just fine.
I am wondering if there is something I can do in the useEffect to avoid this issue.
import React, { useEffect } from "react"
import Layout from "../components/layout"
const Calendly = styled.div`
height: 800px;
margin-top: 100px;
`
const IndexPage = ({ data }) => {
useEffect(() => {
window.Calendly.initInlineWidget({
url: "https://calendly.com/absolute-hardwood",
parentElement: document.getElementById("bookingjs"),
prefill: {},
utm: {},
})
}, [])
return (
<Layout>
<Calendly id="bookingjs" />
</Layout>
)
}
export default IndexPage
Here is how I am adding the Calendly script in my gatsby-confing.js
{
resolve: "gatsby-plugin-load-script",
options: {
src: "https://assets.calendly.com/assets/external/widget.js",
},
}
Marshall here from Calendly. Since you are using React and Gatsby, you can use the react-calendly package to load the inline embed on your site.
You will need to install the react-calendly package in your project, and then import the InlineWidget like this at the top of your file:
import { InlineWidget } from "react-calendly";
Then, you can use the component on your page:
<InlineWidget url="https://calendly.com/your_scheduling_page" />
I hope this helps! Further documentation can be found in the package readme on Github.

Using validate.js to validate my TextInput results in undefined

I am trying to use validate.js to manage my Textfields validations and after installing validate.js and importing it as import validate from 'validate.js'; then adding it to my InputField it seems that the result is undefined.
I tried to reproduce the issue with Expo snack but the following error appears Device: (953:881) Unable to resolve module 'module://validate.js' here is the Expo link:
https://snack.expo.io/#ahmedsaeed/validatetest
Do I miss something here and is there a better way to validate my form?
Here is my code snippet:
import React, { useState, useEffect } from 'react';
import { View } from 'react-native';
import { HelperText } from 'react-native-paper';
import { InputField } from '../../../GlobalReusableComponents/TextFields';
import validate from 'validate.js';
const SkillsAndExperienceScreen = (props) => {
const [company, setCompany] = useState('');
const constraints = {
company: {
presence: true
}
};
const onCompanyChange = (val) => {
const result = validate({company: val}, constraints);
setCompany(val);
}
return (
<View>
<InputField
onChangeText={(val) => onCompanyChange(val)}
value={company}
placeholder='Company'
/>
</View>
);
}
export default SkillsAndExperienceScreen;
const Style = {
container: {
flex: 1,
backgroundColor: '#f8f9f9'
}
};
Thanks in advance.
Update: It seems that the project is showing me the same error
Unable to resolve module `validate` from `/Projects/Seem/src/screens/CompleteYourProfileScreens/SkillsAndExperienceScreen/index.js`: Module `validate` does not exist in the Haste module map.
Looking at the web, it seems import validate from "validate-js" is the way to go. The npm module is https://www.npmjs.com/package/validate-js. I tried it on your expo snack and it worked. But, i think that's an entirely different module.
There might be an expo snack specific problem on it, prolly the ".js" name perhaps?, not quite sure. I tried installing locally to project of mine and it worked.
I would suggest using https://www.npmjs.com/package/#hapi/joi since it's always has been my go to for object validation and it has much better community support, and updates are more frequent.

React + Lottie Animation scroll fire

I created different animation thought Bodymovin. I would like to fire the animation once the scroll reach the animation.
I am trying to figure out the way, but unfortunately I am not able to do it.
I am working with Gatsby JS (React framework). I paste my code down here of the .js file:
import React, { Component } from 'react'
import Lottie from 'react-lottie'
import animationData from './paginaweb.json'
class UncontrolledLottie extends Component {
render(){
const defaultOptions = {
loop: false,
autoplay: true,
animationData: animationData,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
}
};
return(
<div>
<Lottie options={defaultOptions}
width={200}
/>
</div>
)
}
}
export default UncontrolledLottie
I tried libraries as https://www.npmjs.com/package/react-animate-on-scroll but didn't work to me. The animation shows up but it's already fired.
Someone out there that can help me out with this? I will really appreciate.
Thank you
I done similar things with react-waypont. You can place a waypoint somewhere in the page. If your scroll reach it, then you can trigger something. Make sure you just render the animation when this event triggered, so it just starts when you reach there. Something like this.
import {Waypoint} from 'react-waypoint';
import React, {useState} from 'react';
const Component = () => {
let [renderLottie, set] = useState(false);
return (
...
components to push waypoint out of the first page, so you can scroll to it
...
<Waypoint
onEnter={set(true)}
/>
{renderLottie && UncontrolledLottie}
)
}

Categories

Resources