How trigger animation using ref in ReactJS - javascript

here my demo: https://stackblitz.com/edit/react-pwdkse note: use your browser console instead of the Stackblitz's one. Seems the browser console is much more complete in terms of information_feedback
I would trigger animation using ReactJS ref's references instead of changing className inside the element's scope. Currently nothing is happening.
What I may missing?
here my Reacts' snippets:
component
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.module.css';
class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
this.animateRef = React.createRef();
// this.triggerAnimation = this.triggerAnimation.bind(this);
}
componentDidMount(){
// empty scope right now
}
triggerAnimation=()=>{
console.log("trigger animateRef animation")
// this.animateRef.current.style.animationName="animateElement"
// this.animateRef.current.style.animation="1.5s 4.3s 3 alternate forwards"
this.animateRef.current.className.concat(`animation_trigger`)
console.log("animateRef: ", this.animateRef)
}
render() {
return (
<div>
<p>
Start editing to see some magic happen :)
</p>
<div className="animatedElementStyle" ref={this.animateRef}>
I am rendered !
</div>
<button onClick={this.triggerAnimation}>
trigger animation
</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
stylesheet
h1, p {
font-family: Arial;
}
.animatedElementStyle{
position:absolute;
top:61%;
left:10%;
width:15w;
height:25vh;
visibility: hidden;
opacity:0;
}
.animation_trigger{
animation: animateElement 1.5s 0.5s 3 alternate forwards;
}
#keyframes animateElement{
from{
opacity:0;
visibility:hidden;
}
100%{
transform: translate(15%,0);
opacity:1;
visibility:visible;
color:orange;
font-size:3em;
}
}
thanks for any hint

You just have to change this
this.animateRef.current.className.concat(`animation_trigger`)
To:
this.animateRef.current.classList.add(`animation_trigger`);

Related

How to make the content slide smoothly together with the sidebar?[react]

When my sidebar transitions to width: 0, the content right next to it (on its right) doesn't slide with it. It's like the text waits for the sidebar to be done with its animation before it takes the sidebar's place, even though I set its transition as well.
I came up with a minimal reproducible example below:
//Sidebar.js
import './styles/Sidebar.css'
export const Sidebar = () => {
const [show, setShow] = useState(false);
const toggle = ()=>{
setShow(!show);
}
return (
<div>
<div id={'toggle-btn'}>
<button type='button' className='toggle-btn' onClick={toggle}>
toggle
</button>
</div>
<div style={{display:"flex"}}>
<aside className={'sidebar' + (show ? ' showSidebar':'')}>
<ul className='menuList'>
<li>Perfil</li>
<li>Estatísticas</li>
<li>Adicionar Itens</li>
<li>Procurar</li>
</ul>
</aside>
</div>
</div>
)
}
/*Sidebar.css*/
.sidebar {
width:100%;
overflow: hidden;
box-shadow: 0 8px 8px -4px ;
transform: translateX(0);
transition:all 1s ease;
height:100vh;
}
.showSidebar {
width:0;
}
//Dashboard.js
import './styles/Dashboard.css'
export const Dashboard = () => {
return (
<div className='dashboard'>
<p>
LORE IPSUM BLA BLA
</p>
</div>
)
}
/*Dashboard.css*/
.dashboard {
max-width: 30%;
margin-top:10rem;
transition:all 1s ease;
}
//App.js
function App() {
return (
<div style={{display:"flex"}}>
<Sidebar />
<Dashboard />
</div>
);
}
export default App;
When you change the Sidebar's width from 100% to 0, it simply is taken out of the content flow, and Dashboard then is reposition to left. To make Sidebar and Dashboard transition together while one of the two has width change, you need to establish a relationship between the two component's widths.
Please refer to this CodeSandbox example I put together for you.
In it, I set up a global CSS variable like below:
/* styles.css */
:root {
--sidebar: 150px;
}
And use it in both Sidebar and Dashboard like below:
/* Sidebar.css */
.sidebar {
width: var(--sidebar);
/* no other changes */
}
/* Dashboard.css */
.dashboard {
width: calc(100% - var(--sidebar));
/* no other changes */
}
With the above, whenever Sidebar's width changes, it'll reflect the value in Dashboard's width, making both transition in sync.

Animations stop working after building and deploying to Firebase

I'm having a problem where my animations stop working once I npm run-script build and firebase deploy my react app to Firebase hosting.
No idea why this is happening, I've added every web browser compatible keyframes.
Here's what my app looks like when ran on localhost (npm start):
And then what it looks like hosted from firebase:
It's like it can't read my keyframe animations.
Here's index.js:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { createStore, applyMiddleware, compose, combineReducers } from "redux";
import thunk from "redux-thunk";
import * as serviceWorker from "./serviceWorker";
import userReducer from "./store/reducers/user";
import { WithClass } from "./hoc/WithClass";
import classes from "./index.module.css";
import App from "./App";
// Icons made by Freepik from www.flaticon.com
// Reducers
const rootReducer = combineReducers({
user: userReducer,
});
// Store
const store = createStore(rootReducer, applyMiddleware(thunk));
const app = (
<Provider store={store}>
<WithClass>
<BrowserRouter>
<App />
</BrowserRouter>
</WithClass>
</Provider>
);
ReactDOM.render(app, document.getElementById("root"));
App.js:
import React from "react";
import { Route, Switch, withRouter, Redirect } from "react-router-dom";
import HomePage from "./pages/HomePage/HomePage";
import AboutPage from "./pages/AboutPage/AboutPage";
import WorkPage from "./pages/WorkPage/WorkPage";
import PhotographyPage from "./pages/PhotographyPage/PhotographyPage";
import ContactPage from "./pages/ContactPage/ContactPage";
import { WithClass } from "./hoc/WithClass";
/**
* Contains switch routing to components
*
* Called by index.js in ReactDOM.render()
*/
const App = () => {
return (
<WithClass>
<Switch>
<Route path="/about" exact component={AboutPage} />
<Route path="/work" exact component={WorkPage} />
<Route path="/photography" exact component={PhotographyPage} />
<Route path="/contact" exact component={ContactPage} />
<Route path="/" exact component={HomePage} />
<Redirect to="/" />
{/* Redirect anything other than routes specified to "/" */}
</Switch>
</WithClass>
);
};
export default withRouter(App);
HomePage.js:
import React, { useEffect } from "react";
import AnimatedSlideShowText from "../../components/UI/AnimatedSlideShowText/AnimatedSlideShowText";
import HeaderAnimated from "../../components/UI/HeaderAnimated/HeaderAnimated";
import HeaderStatic from "../../components/UI/HeaderStatic/HeaderStatic";
import SocialMediaFooter from "../../components/UI/SocialMediaFooter/SocialMediaFooter";
import { useDispatch, useSelector } from "react-redux";
import { loadedOnce } from "../../store/actions/user";
import classes from "./HomePage.module.css";
const HomePage = () => {
const dispatch = useDispatch();
const didLoadOnce = useSelector((state) => state.user.loadedOnce);
useEffect(() => {
setTimeout(() => {
dispatch(loadedOnce());
}, 2000);
}, []);
return (
<div className={classes.MainContainer}>
<div className={classes.HeaderContainer}>
{didLoadOnce ? <HeaderStatic /> : <HeaderAnimated />}
</div>
<div className={classes.BodyContainer}>
<div className={classes.NameContainer}>
<AnimatedSlideShowText tag="h1">
Christian Nicoletti
</AnimatedSlideShowText>
<AnimatedSlideShowText
tag="h2"
mainTextStyle={classes.Title}
>
Software Engineer
</AnimatedSlideShowText>
<AnimatedSlideShowText
tag="h3"
mainTextStyle={classes.School}
>
University of California, Santa Cruz graduate
</AnimatedSlideShowText>
</div>
<div className={classes.FooterContainer}>
<SocialMediaFooter />
</div>
</div>
</div>
);
};
export default HomePage;
HomePage.module.css:
.MainContainer {
width: 100vw;
height: 100vh;
min-width: 1500px;
}
.BodyContainer {
display: flex;
height: 100%;
justify-content: center;
margin-left: 20%;
flex-direction: column;
}
.NameContainer {
display: flex;
height: 250px;
width: 500px;
}
.Title {
margin-top: 60px;
-webkit-animation-delay: 0.2s;
animation-delay: 0.2s;
}
.School {
margin-top: 120px;
-webkit-animation-delay: 0.3s;
animation-delay: 0.3s;
}
.HeaderContainer {
position: absolute;
right: 100px;
}
.FooterContainer {
width: 500px;
}
AnimatedSlideShowText.js:
import React from "react";
import classes from "./AnimatedSlideShowText.module.css";
const AnimatedSlideShowText = (props) => {
const CustomTag = `${props.tag}`;
return (
<CustomTag className={`${classes.MainText} ${props.mainTextStyle}`}>
{props.children}
</CustomTag>
);
};
export default AnimatedSlideShowText;
AnimatedSlideShowText.module.css:
.MainText {
color: white;
position: absolute;
opacity: 0;
margin-left: -10%;
font-family: Calibri;
font-weight: 300;
-webkit-animation: slide 0.5s forwards;
animation: slide 0.5s forwards;
}
#-o-keyframes slide {
100% {
margin-left: 0%;
opacity: 100%;
}
}
#-ms-keyframes slide {
100% {
margin-left: 0%;
opacity: 100%;
}
}
#-moz-keyframes slide {
100% {
margin-left: 0%;
opacity: 100%;
}
}
#-webkit-keyframes slide {
100% {
margin-left: 0%;
opacity: 100%;
}
}
#keyframes slide {
100% {
margin-left: 0%;
opacity: 100%;
}
}
#-webkit-keyframes show {
/* Chrome, Safari */
0% {
width: 100%;
}
100% {
width: 0%;
}
}
#-moz-keyframes show {
/* FF */
0% {
width: 100%;
}
100% {
width: 0%;
}
}
#-ms-keyframes show {
/* IE10 */
0% {
width: 100%;
}
100% {
width: 0%;
}
}
#-o-keyframes show {
/* Opera */
0% {
width: 100%;
}
100% {
width: 0%;
}
}
#keyframes show {
0% {
width: 100%;
}
100% {
width: 0%;
}
}
I'd add more component source code, but I think AnimatedSlideShowText is all that is needed to understand the problem.
So again, I'm just trying to get my animations to work when built and deployed. I'm not sure why they would stop working when built and deployed.
Is it possible that using module.css has an impact on animations when built/deployed? Any help would be super appreciated, and if you need more source code let me know.
I've had a similar problem before but I was using a CSS framework. The problem was with the build cache on my hosting provider. When using create-react-app (that uses Webpack), on the build stage happens the so called 'tree-shake'. It gets rid of unused styles, classes etc from your modules.
A module that works locally might not work on production because it was rid off on your first build and is then not used on the new build due to the build cache.
I don't know if it's the solution to your problem but I suggest you check it out since it worked for me in the past.
Ok so! I managed to fix it. I thought this was a lot more complex than it actually was.
Short answer: I had to change all my opacity: 100% to opacity: 1 and suddenly everything appeared and worked correctly.
Long answer: I had to dabble in the console for a bit, and realized that all my components and text were there, but just not showing up. I played with the animations by disabling and re-enabling, and stuff would flicker for a second. I realized that it was rendering the opacity as: opacity: 1% instead of opacity: 100%. Apparently, when building with npm run-script build, it acts as if 100% has trailing zeros(??).
Anyway, I appreciate the help, and everything works perfectly now.

Binding button with keypress in Vue3.0

I am trying to trigger the button when mouse clicked it or a key is pressed and I get confused about communication between components. How should I call pressDown() in KeyButton component from its father component, or is there a better way to implement this function?
Here's my attempt
Container of button
<template>
<key-button :message="'Msg'" :callback="pressKey" ></key-button>
</template>
<script setup>
import KeyButton from "./KeyButton.vue";
import {ref,onMounted} from "vue";
onMounted(()=>{
addEventListener('keypress',(e)=>{
//trigger button
});
})
const pressKey = () => {
//exec when button clicked
}
</script>
KeyButton Component
<template>
<button class="button" :class="{'animate': active}" v-on="{mousedown:pressDown,animationend:triggerAnim}">{{props.message}}</button>
</template>
<script setup>
import {ref,defineProps} from 'vue';
const props = defineProps({
message: String,
callback: Function
})
const active = ref(false);
//Function to trigger button
const pressDown = ()=>{
props.callback();
triggerAnim();
}
const triggerAnim = ()=>{
active.value = !active.value;
}
</script>
<style scoped>
button{
display: flex;
height: 5rem;
width: 5rem;
justify-content: center;
align-items: center;
font-size: 2rem;
color: white;
border-color: deepskyblue;
border-width: 0.15rem;
border-radius: 50%;
background-color: lightskyblue;
margin-bottom: 1rem;
margin-left: 2rem;
outline: none !important;
}
.animate{
animation: zoom 0.2s;
}
#keyframes zoom {
0%{
transform: scale(1);
}
10%{
transform: scale(0.9);
}
100%{
transform: scale(1);
}
}
</style>
You shouldn't pass methods as props in vue as this creates interdependencies among the components and makes them less reusable.
Instead of passing the method you should emit an event from the KeyButton Component on keypress and listen to it in the parent component, like so:
// KeyButton Component
<button #click="$emit('button-pressed')" />
// Parent
<KeyButton #button-pressed="pressKey" />
You should not pass callbacks as props between components. Vue has a pattern to share functions between components: enter link description here, provide/inject pattern.
Although, I suggest you follow the approach Aside gave to you, and work with event handling provided by vue by emitting an event on child component to the parent.

Components not animating with react-transition-group, just updates instantly?

I'm trying to animate a sidebar component following the first section on this page. When I follow this the component doesn't animate, but simply mounts/unmounts.
The component SidePage is as follows:
import React from "react"
import { TransitionGroup, CSSTransition } from "react-transition-group"
import "./sidePage.css"
class SidePage extends React.Component {
componentWillMount() {
console.log("will mount")
}
componentDidMount() {
console.log("did mount")
}
componentWillUnmount() {
console.log("will unmount")
}
render() {
const { content, sidePageOpen } = this.props
return (
<TransitionGroup component={null}>
{sidePageOpen && (
<CSSTransition key={content.id} classNames="sidepage" timeout={2000}>
<div
key={content.id}
className="sidepage"
dangerouslySetInnerHTML={{ __html: content.html }}
/>
</CSSTransition>
)}
</TransitionGroup>
)
}
}
export default SidePage
and the css file:
.sidepage-enter {
opacity: 0;
}
.sidepage-enter-active {
opacity: 1;
transition: all 2s;
}
.sidepage-exit {
opacity: 1;
}
.sidepage-exit-active {
opacity: 0;
transition: all 2s;
}
.sidepage {
background: white;
padding: 10px;
height: 100%;
width: 90vw;
position: absolute;
top: 0;
right: 0;
z-index: 10;
opacity: 0.4;
transition: all 0.6s;
}
Basic stuff I think — the sidePageOpen is a boolean state passed down, I have a button on another page that toggles this state. If anyone has any ideas/suggestions that would be brilliant and appreciated.
Remove the opacity property from sidepage class.
.sidepage {
background: white;
padding: 10px;
height: 100%;
width: 90vw;
position: absolute;
top: 0;
right: 0;
z-index: 10;
opacity: 0.4; // remove me
transition: all 0.6s;
}
The element get's added with a class of sidepage which has a opacity of 0.4, thats whats breaking the animation. Working demo here
Eventually found the solution — I had a styled <Wrapper> div created using emotion.sh styled components, I was using this to contain all of my content, not sure why but this didn't allow any animations — changing this to a simple <div> seemed to fix it.
Edit: Probably because it was recreating the Wrapper component on every state change.

Spinner not working vue.js

I use this package: https://github.com/greyby/vue-spinner for showing a spinner.
<template>
<pulse-loader :loading="loading" :color="color" :size="size"></pulse-loader>
</template>
<script>
import { PulseLoader } from 'vue-spinner/dist/vue-spinner.min.js';
export default {
components: { PulseLoader },
data () {
return {
loading: true,
color: "black",
size: "10"
}
}
}
</script>
For some reason the spinner is not showing???!?! There are no erros in my console!
You should not be importing from the dist folder.
Please, try importing the vue component source, doing as shown in the documentation:
import PulseLoader from 'vue-spinner/src/PulseLoader.vue'
Docs: https://github.com/greyby/vue-spinner#es6
UPDATE:
Considering Browserify restriction on applying transforms in files inside node_modules, then you could try the code snippet provided in the mentioned GitHub issue:
var PulseLoader = require('vue-spinner/dist/vue-spinner.min').PulseLoader;
The website I was working on had a custom CSS-file. It was missing the correct styles. Possibly because it was for an older version of Bootstrap.
Make sure that there is a definition for .spinner-border anywhere in your styles. If not, find out why not and fix it.
I have copied the style from the source-code of the Vue examples page for a quick fix.
#keyframes spinner-border {
to { transform: rotate(360deg); }
}
.spinner-border {
display: inline-block;
width: 2rem;
height: 2rem;
vertical-align: text-bottom;
border: .25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
-webkit-animation: spinner-border .75s linear infinite;
animation: spinner-border .75s linear infinite;
}

Categories