ReactJS: Fade in div and fade out div based on state - reactjs

So, I am trying to fade in and fade out a set of inputs based on what button the user clicks. I tried using jQuery, but, the div was fading in and fading out at the same speed...
I am using es6 classes and react.
What I want is the user to press a button and the inputs fadeIn. Another button, the inputs fadeOut. I don't mind using jQuery, but I would like to understand how to do this with react.
renderInputs() {
if (this.state.addType === "image") {
return (
<div className="addContainer">
<input type="text" className="form-control" />
</div>
)
} else {
return (
other inputs
)
}
}
render() {
return (
<CSSTransitionGroup
transitionName="fadeInput"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{this.renderInputs()} // this doesn't work but I want this content to be conditional.
</CSSTransitionGroup>
)
}
// SCSS
.fadeInput-enter {
opacity: 0.01;
}
.fadeInput-enter.fadeInput-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.fadeInput-leave {
opacity: 1;
}
.fadeInput-leave.fadeInput-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}

Just use a conditional class and CSS.
Have a state variable like visible.
this.state = {
visible:false
}
And for the other inputs do something like
<input className={this.state.visible?'fadeIn':'fadeOut'} />
So depending upon the state.visible the input will have a class of either fadeIn or fadeOut.
And then just use simple CSS
.fadeOut{
opacity:0;
width:0;
height:0;
transition: width 0.5s 0.5s, height 0.5s 0.5s, opacity 0.5s;
}
.fadeIn{
opacity:1;
width:100px;
height:100px;
transition: width 0.5s, height 0.5s, opacity 0.5s 0.5s;
}
So every time the state.visible changes the class changes and the transition takes place. The transition property in CSS is basically all the transitions separated by commas. Within the transition the first argument is the property to be modified (say height, width etc), second is transition-duration that is the time taken for the transition and third(optional) is transition-delay ie how much time after the transition has been initiated does the transition for the particular property take place. So when this.state.visible becomes true the .fadeIn class is attached to the object. The transition has height and width taking 0.5s each so that will take 0.5s to grow and after it is finished the opacity transition (which has a delay of 0.5s) will trigger and take a further 0.5s to get opacity 1. For the hiding it's the reverse.
Remember to have the OnClick event on the button handle the changing of this.state.visible.

You could also achieve this with CSSTransitionGroup
const Example = ({items, removeItemHandler}) => {
return (
<div>
<CSSTransitionGroup transitionName="fadeInput"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{this.renderInputs().map(function(input) {
return (
<div key={input.id} className="my-item" onClick={removeItemHandler}>
{item.name}
</div>
);
})}
</ReactCSSTransitionGroup>
</div>
);
};
When working with React, sometimes you want to animate a component directly after it has been mounted, or directly prior to it being unmounted.
Like in your example, Let’s say you map over an array of objects and render a list in your application. Now let’s say you want to add animations to fade-in new items that have been added to the array or fade-out items as they are removed from the array.
The CSSTransitionGroup component takes in transitionEnterTimeout and transitionLeaveTimeout as props. What these values represent are the duration in milliseconds of your enter and leave transitions.

A simple way to achieve this with styled components...
const Popup = styled.div`
width: 200px;
height: 200px;
transition: opacity 0.5s;
opacity: ${({ showPopup }) => (showPopup ? '1' : '0')};
`;
<Popup showPopup={showPopup}>
{...}
</Popup>

Related

How to change the Swiper height or slide width in React JS without using fixed CSS

I have a card game where the player selects a card from one deck to add to a second. Pushing the button on the active card will move it to the other deck and then make it active. The active deck should be larger when in focus, while the inactive is minimized like so:
I have implemented it using the Swiper Coverflow effect in both SwiperJS and React-Swiper, but in either case the height is tied to the .swiper-slide CSS class. The width on this class is set to a fixed size which drives how the rest of the Swiper is rendered. It seems that the only way to change the slide width (and resulting Swiper height) is to apply fixed width classes to the slide based on state.
JSX:
<SwiperSlide
key={index}
className={
props.selected
? "swiper-fixed-width-300 "
: "swiper-fixed-width-100 "
}
>
CSS:
.swiper-fixed-width-100 {
width: 100px;
}
.swiper-fixed-width-300 {
width: 300px;
}
However this approach has no easing or transition like other interactions so it feels too abrupt. I would like to find a way to do the same using the Swiper API functions. How can this same interaction be achieved with the API or without manipulating the CSS class?
Example Sandbox
I would use transform: scale(0.3) on the parent (Deck) and keep the width of the slider at 300px.
JSX (Deck.js):
<div
className={
props.selected
? "Deck Deck-selected"
: "Deck Deck-unselected"
}
>
<SwiperSlide key={index} className="swiper-fixed-width-300">
CSS:
.Deck {
transition: transform 0.3s ease;
}
.Deck-selected {
transform: scale(1);
}
.Deck-unselected {
transform: scale(0.3);
}
.swiper-fixed-width-300 {
width: 300px;
}
Here is my sandbox with the effect transitioning.
If you want to change the size of the "decks" and maintain a smooth transition effect, I am thinking you could use the scale() transform function which is also a CSS solution.
https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale()#examples
If you combine this with a CSS transition you can achieve the effect you mentioned.
Here is a blog post from thoughtbot.com that dives into using scale() and CSS transitions:
https://thoughtbot.com/blog/transitions-and-transforms

How to add a smooth sliding transition effect to a react-bootstrap based Column component?

To summarize the problem, I am trying to work through a component that has 2 columns (react-bootstrap Column component). The left container being collapsible and the right always there. On a click of a button, I will toggle show/hide on the left column. It works fine but the behavior is rugged. Whereas, I want to add a transition effect to achieve a smoother slide behavior.
More info...I have a page where I want to display products and filter the products based on different properties such as cost, size, category etc. So, I use a container inside and got 2 columns inside it a row.
Problem: Transition not so smooth...
Something like this in the code below,
import React, { Component } from 'react';
import { ProductsViewFilter } from '../../Controls/ProductsViewFilter/ProductsViewFilter';
import { ProductsView } from '../../Controls/ProductsView/ProductsView';
import { Container, Row, Col, Collapse } from 'react-bootstrap';
import './ProductsViewContainer.css';
export class ProductsViewContainer extends Component {
constructor(props) {
super(props);
this.state = {
filterExpanded: false
}
}
render() {
return (
<Container className='products-view-filter-container'>
<Row>
<Collapse in={this.state.filterExpanded}>
<Col sm={2} className={this.state.filterExpanded ? 'products-view-filter products-view-filter-transition-slide-in' : 'products-view-filter products-view-filter-transition-slide-out'}>
<ProductsViewFilter></ProductsViewFilter>
</Col>
</Collapse>
<Col className='products-view-container-productsview'>
<div className='slider-icon-div' >
<img className='slider-icon' src='/images/icons/slider.svg'
onClick={(e) => { e.preventDefault(); this.setState({ filterExpanded: !this.state.filterExpanded }); }} />
</div>
<ProductsView></ProductsView>
</Col>
</Row>
</Container>);
}
}
.products-view-filter-container
{
max-width: 100% !important;
}
.products-view-filter
{
background-color: wheat;
transform: translateX(-150px);
transition: transform 400ms ease-in;
}
.products-view-filter-transition-enter
{
transform: scale(0.8);
opacity: 0;
}
.products-view-filter-transition-enter-active
{
opacity: 1;
transform: translateX(0);
transition: opacity 300ms, transform 300ms;
}
.products-view-filter-transition-exit
{
opacity: 1;
}
.products-view-filter-transition-exit-active
{
opacity: 0;
transform: scale(0.9);
transition: opacity 300ms, transform 300ms;
}
.products-view-filter-transition-slide-in {
transform: translateX(0);
}
.products-view-filter-transition-slide-out {
transform: translateX(-100%);
}
.products-view-container-productsview
{
background-color: lavender;
}
.slider-icon
{
height: 1.5rem;
}
.slider-icon:hover
{
cursor: pointer;
}
.slider-icon-div
{
margin-top: 15px;
text-align: left;
}
I would like to see the behavior as something like https://codepen.io/bjornholdt/pen/MpXmmL/.
I know this is easily achievable by using bunch of pure divs. But, my desire is to use bootstrap components as it responsive in mobile devices.
Any advice, suggestion as to how to achieve sticking to Col and Row components with a smooth transitions will be really helpful.
This might be too late, but in case anyone else has this issue...
I have not tested this myself, but try what the docs (https://react-bootstrap.github.io/utilities/transitions/) suggest.
...
Collapse#
Add a collapse toggle animation to an element or component.
Smooth animations
If you're noticing choppy animations, and the component that's being collapsed has non-zero margin or padding, try wrapping the contents of your inside a node with no margin or padding, like the in the example below. This will allow the height to be computed properly, so the animation can proceed smoothly.
...

CSSTransition from react-transition-group does not exit

Trying to get used CSSTransiction component. I need to show a panel which is animated by using css-classes. The first class defines the primary location, the second defines position when the panel is opened (top: 0).
Appearing is working, but exiting does not. onEntered fires, onExied does not.
There is lack of documentation for CSSTransition component, I tried different combinations, but without success. Any ideas?
CSS:
.getSecondLevelPanel{
position: fixed;
left: 450px;
top: -100%;
height: 100%;
width: 400px;
transition: all 250ms ease-out;
}
.getSecondLevelPanelOpened {
top: 0;
}
React component:
import * as React from 'react';
import { CSSTransition } from 'react-transition-group';
export interface Props {
isVisible: Boolean;
children: React.ReactChild;
onClose: () => void;
}
const SecondLevelPanel = (props: Props) => {
return (
<CSSTransition
timeout={{
enter: 0,
exit: 500
}}
in={props.isVisible}
appear={true}
enter={true}
exit={true}
classNames={{
appear: 'getSecondLevelPanel',
enterDone: 'getSecondLevelPanel getSecondLevelPanelOpened',
exit: 'getSecondLevelPanel'
}}
unmountOnExit={true}
onEntered={() => {
alert('entered');
}}
onExited={() => {
alert('exited');
}}
>
<div>
<a onClick={() => props.onClose()}>Close</a>
{props.children}
</div>
</CSSTransition>
);
};
export default SecondLevelPanel;
After searching for answers for sometime, I realised my problem had to do with my toggle function (onClick={() => props.onClose()} in your case).
It seems my toggle function was not working as it was supposed to. Since onEntered is triggered with "in{true}" and onExited is triggered with "in{false}", you have to make sure the boolean is being changed with each click on your anchor tag.
Looking at your code is seems your onClose function only returns a void function instead of a toggle. Try toggling between true and false and pass that into the in{//toggle function} param.
The problem is in your CSS and classNames props on you. The CSSTransition component applies the classes like so.
appear and enter classes are added as soon as the in prop is set to true.
appear-active and enter-active are added right after the appear and enter classes are set.
appear-done and enter-done are added after the duration set in the timeout passed.
the exit classes repeat Step 1-3 just after the in prop is set to false.
The reason your exit calls don't work is probably due to only setting one exit class and 0 set to your enter duration. Try setting your transition rule on the active classes to ensure that the transition is set for the whole duration of the transition and separate the moving parts from the static ones. Like so
.panel{
position: fixed;
left: 450px;
top: -100%;
height: 100%;
width: 400px;
}
.panel-appear,
.panel-enter {
top: -100%;
}
.panel-appear-active,
.panel-enter-active {
top: 0;
transition: all 250ms ease-out;
}
.panel-exit {
top: 0;
}
.panel-exit-active {
top: -100%
transition: all 250ms ease-out;
}
Take a look at this codepen, this is how I create a panel transitions.
Install:
npm install react-transition-group
Usage:
import { CSSTransition } from 'react-transition-group';
<CSSTransition
in={toShow} // boolean value passed via state/props to either mount or unmount this component
timeout={300}
classNames='my-element' // IMP!
unmountOnExit
>
<ComponentToBeAnimated />
</CSSTransition>
NOTE: Make sure to apply below styles using the class property in CSS:
.my-element-enter {
opacity: 0;
transform: scale(0.9);
}
.my-element-enter-active {
opacity: 1;
transform: translateX(0);
transition: opacity 300ms, transform 300ms;
}
.my-element-exit {
opacity: 1;
}
.my-element-exit-active {
opacity: 0;
transform: scale(0.9);
transition: opacity 300ms, transform 300ms;
}

Trying to use ReactCSSTransitionGroup for a Singleton

I'd like to move something bottom: +/- 100px.
So that when focused, it slides up. When unfocused, it slides back down.
I've created this React render() :
var component = (
<div key={"trayResponder_" + this.props.trayOpen} >
</div>
);
return(
<ReactCSSTransitionGroup transitionName="tray-responder">
{component}
</ReactCSSTransitionGroup>
);
And then I toggle it's key state, by updating this.props.trayOpen
And then my Less is like this :
.tray-responder-enter {
}
.tray-responder-enter-active {
.animation(slideUp 1s ease infinite )
}
.tray-responder-leave {
}
.tray-responder-leave-active {
.animation(slideDown 1s ease infinite )
}
.keyframes(slideUp;{
0% {transform: translateY(100%);}
50% {transform: translateY(-8%);}
65% {transform: translateY(4%);}
80% {transform: translateY(-4%);}
95% {transform: translateY(2%);}
100% {transform: translateY(0%);}
});
.keyframes(slideDown;{
0% {transform: translateY(-100%);}
50%{transform: translateY(8%);}
65%{transform: translateY(-4%);}
80%{transform: translateY(4%);}
95%{transform: translateY(-2%);}
100% {transform: translateY(0%);}
});
Which adopts from animation.less :
.keyframes(#name; #arguments) {
#-moz-keyframes #name { #arguments(); }
#-webkit-keyframes #name { #arguments(); }
#keyframes #name { #arguments(); }
}
.animation(#arguments) {
-webkit-animation: #arguments;
-moz-animation: #arguments;
animation: #arguments;
}
Unfortunately, this doesn't seem to work. Nothing occurs. No animation. Not really sure why.
Update
The trouble with ReactCSSTransitionGroup is that enter-active and leave-active occur simultaneously. Which doesn't seem to be a problem if you're toggling opacity. But if you're moving things up and down like I am, then you see both at the same time.
As seen here :
As much as I understand, CSS Transition is for enter and leave. You want animation on hover, which can probably be achieved by using :hover selector.
const TransitionDemo = React.createClass({
render : function () {
return(
<div className="demo">
<p>Some Text Here</p>
</div>
);
}
});
ReactDOM.render(<TransitionDemo trayOpen={1}/>, document.getElementById('root'));
//css
.demo {
height : 100px;
position : relative;
}
.demo p {
position : absolute;
bottom : 0px;
transition : all 1s ease;
}
.demo:hover > p{
bottom : 50px;
transition : all 1s ease;
}
See this pen : http://codepen.io/umgupta/pen/dNNLxL

Enable fade animation on ng-show but disable animation on hide

So, I want the animation to only apply when ng-show is true. I'm having a hard time trying to disable a "fade out" effect. In jQuery this is simply $.hide and not $.fadeOut. How do I achieve this in Angular?
http://jsfiddle.net/7twjd3an/2/
CSS
.fadeIn {
-webkit-transition:all linear 0.25s;
transition:all linear 0.25s;
}
.fadeIn.ng-hide {
opacity:0;
}
.fadeIn.ng-show {
opacity: 1;
}
You can add different transitions for .ng-show and .ng-hide
Adding the following to .ng-hide would remove the transition styles when you hide the element while retaining the existing transition styles when you show the element:
.ng-hide {
opacity: 0;
transition: none 0;
}

Resources