I am quite new to react and I am trying to build a react app. I want a login box to fade in on the page when the login in the navbar is clicked. In my App.js I set up the CSSTransitionGroup like this:
<CSSTransitionGroup
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
transitionAppear={true}
transitionAppearTimeout={500}
transitionName="fade">
{loginPopup}
</CSSTransitionGroup>
The login popup is shown based on state:
let loginPopup;
if (display_login) {
loginPopup = (<LoginPopup key={1} />)
}
Now the css I use for the transition looks like this:
//fade
.fade-appear {
opacity: 0.01;
}
.fade-appear-active {
opacity: 1;
transition: opacity 300ms ease-in;
}
.fade-leave {
opacity: 1;
}
.fade-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
My problem is...that the fadeout works as intended, but the fadein does not work. It just pops up (no transition).
I also tried using .fade-enter - But I figured that enter was wrong as the LoginPopup component is spawned based on state.
Any ideas why the fade in don't work?
Edit:
This is the gist of the code: https://gist.github.com/xenoxsis/6345eb6897aedf228662ffaf64f65053
Related
I'm trying to apply animation: smooth disappearing old text and smooth appearing the new one.
Now I created it with useEffect hooks and with inner Transition: onExited function
Furthermore I have not only title value, and my solution seemed to me the duct tape.
const [toggle, setToggle] = useState(true)
const [exited, setExited] = useState(false)
const [title, setTitle] = useState(service.title) //default value
useEffect(() => {
setExited(false) //set default value
setToggle(false)
}, [service]) //unmount node with old text (toggle this hook with changing another **service**)
useEffect(() => {
setToggle(true)
setTitle(service.title)
}, [exited]) //appear after old text unmounted
Node:
<Transition
in={toggle} timeout={500}
mountOnEnter unmountOnExit
onExited={() => setExited(true)}
>
{ state =>
<div className={classes['Services__card-categories-title'] + ' ' + classes[state]}>
{title}
</div>
}
</Transition>
Styles:
.entering{
animation: appearing .5s linear;
}
.exiting{
animation: appearing .5s linear reverse;
}
#keyframes appearing {
0%{
opacity: 0;
}
100%{
opacity: 1;
}
}
How to make it universal using react-transition-group library functionality ?
P.S. One more trouble is transition triggering not depends on single value, if any value is changed -> transition will triggered on every element
I use styled-components alongside React and I have such component:
import styled, { keyframes } from 'styled-components'
import { ReactComponent as SpinnerIcon } from './spinner.svg'
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`
const Spinner = styled(SpinnerIcon)`
margin-top: 50px;
animation: ${rotate} 2s ease-in infinite;
`
export default Spinner
When I use this component like this:
<Spinner width='50px' height='50px' />
I see this component but it's not animating. What's wrong?
Try this:
const Spinner = styled.img.attrs({
src: SpinnerIcon,
})`
margin-top: 50px;
animation: ${rotate} 2s ease-in infinite;
if this doesn't work for you please share your svg file too. Also you probably need use linear function instead of ease-in
`
I wrote some pieces of codes in angular about rotating an icon by pressing a toggle button in angular.
When I run it in chrome everything is OK but in Edge rotation process works properly but final rotation status is 180 degree reverse.
Here is my snippets:
my .ts file:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-menutest',
templateUrl: './menutest.component.html',
styleUrls: ['./menutest.component.scss']
})
export class MenutestComponent implements OnInit {
public classChangesRotation: {[key: string]: string} = {};
public expandeds: {[key: string]: boolean} = {};
private zero: string;
constructor() {
this.zero = 'zero';
this.expandeds[this.zero] = true;
this.classChangesRotation[this.zero] = 'rotate-expanded';
}
expansion_click(divName: string) {
this.expandeds[divName] = !this.expandeds[divName];
if (this.expandeds[divName]) {
this.classChangesRotation[divName] = 'rotate-expanded';
} else {
this.classChangesRotation[divName] = 'rotate-collapsed';
}
}
}
my html file:
<button mat-raised-button (click)="expansion_click('zero')">
Expand and Collapse
<mat-icon [ngClass]="classChangesRotation['zero']">
chevron_left
</mat-icon>
</button>
and my scss file contains :
.rotate-expanded {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
transition: -webkit-transform 150ms;
transition: transform 150ms;
transition: transform 150ms,-webkit-transform 150ms;
transition-timing-function: ease-in-out;
}
.rotate-collapsed {
-webkit-transform: rotate(0);
transform: rotate(0);
transition: -webkit-transform 150ms;
transition: transform 150ms;
transition: transform 150ms,-webkit-transform 150ms;
transition-timing-function: ease-in-out;
}
As I mentioned above when I run these codes in chrome everything is OK and normal but in Edge the animation process is fine but final rotation differs 180 degrees!
Do you have any idea?
Thank you for your attentions.
Pay attention please:
You should know that direction of this code is right to left and result in LTR direction is OK but the problem is in RTL direction. I understand it right now and added it to my question.
I'm working on building a component that displays none or block depending on it's isActive prop.
I've managed to make it slideInDown using react-animations with styled-components like this.
import styled, { keyframes } from 'styled-components';
import { ifProp } from 'styled-tools';
import { slideInDown } from 'react-animations';
const slideInAnimation = keyframes`${slideInDown}`;
const MyComponent = styled.div`
animation: 0.4s ${slideInAnimation};
display: ${ifProp('isActive', 'block', 'none')};
`;
I need to make it slideOutUp now. However, I'm not sure how to implement both slideInDown and slideOutUp animations together.
How would I accomplish that?
Note: that works. But I don't know how to make it both slide in and out. I tried something like this below but that didn't work.
import styled, { keyframes } from 'styled-components';
import { ifProp } from 'styled-tools';
import { slideInDown, slideOutUp } from 'react-animations';
const slideInAnimation = keyframes`${slideInDown}`;
const slideOutAnimation = keyframes`${slideOutUp}`;
const MyComponent = styled.div`
animation: 0.4s ${slideInAnimation}, 0.4s ${slideOutAnimation};
display: ${ifProp('isActive', 'block', 'none')};
`;
I went through the react-animations library, what I figured out is slideOutUp sets visibility: 'hidden.'
const slideOutUp: Animation = {
from: {
transform: translate3d(0, 0, 0)
},
to: {
visibility: 'hidden',
transform: translate3d(0, '-100%', 0)
}
};
You can use animation-fill-mode: forwards, which helps in retaining the style after the animation ends.
You can do something like this (it works):
const MyComponent = styled.div`
animation: ${ifProp(
"isActive",
`0.4s ${slideInAnimation}`,
`0.4s ${slideOutAnimation} forwards`
)};
`;
Here is the working example, for testing purpose onClick event I am setting {isActive: false}
https://codesandbox.io/s/949ql6p6no
Display does not animate. You need to use opacity for toggling (1 to 0 and vice versa) and animation.
const myComponent = styled.div`
animation: 0.4s ${slideInAnimation};
opacity: ${ifProp('isActive', 1, 0)};
`;
Considering that your code is working like you told me, you can use the attribute infinte at animation:
animation: 0.4s ${slideInAnimation} infinite;
I guess that it solves your problem.
I have a component that gets unmounted after ten seconds, and I just can't seem to get the leave-animations working with React CSSTransitionGroup. The appear classes gets added when the component mounts and those animations work well. However, the leave classes never gets added to the component on unmount. I've found several working jsfiddle examples, but the code doesn't work for me. I'm new to React so I'm hoping that someone can point me in the right direction. I've set the timeouts to be able to see if the classes gets added.
Main component:
this.state = {
renderBlankSlate: true,
//the rest of the initial state..
}
// This unmounts the component
componentDidMount() {
this.interval = setTimeout(() => this.setState({renderBlankSlate: false}), 10000);
}
{ this.state.renderBlankSlate ?
<ReactCSSTransisionGroup
component="div"
transitionName="slide"
transitionEnterTimeout={ 500 }
transitionAppear={ true }
transitionAppearTimeout={ 2000 }
transitionLeaveTimeout={ 5000 }
>
<BlankSlate />
</ReactCSSTransisionGroup>
: null }
CSS:
.slide-appear {
transform: translateX(110%);
height: 0;
opacity: 0;
}
.slide-appear.slide-appear-active {
transform: translateX(0);
height: 100%;
opacity: 1;
transition: all 2s ease-in;
}
.slide-leave {
transform: translateX(0);
}
.slide-leave.slide-leave-active {
transform: translateX(110%);
transition: 5s ease-in;
}
You probably want to add that ternary within the transition group.
<ReactCSSTransitionGroup
component="div"
transitionName="slide"
transitionEnterTimeout={ 500 }
transitionAppear={ true }
transitionAppearTimeout={ 2000 }
transitionLeaveTimeout={ 5000 }
>
{this.state.renderBlankSlate ? <BlankSlate /> : null}
</ReactCSSTransitionGroup>
The reason your leave animation isn't firing is because the Transition group is leaving as well