React element width animation - javascript

In my React based application I'm trying to perform a simple css3 width transition like:
.foo {
transition: width 1s ease-in-out;
}
what I want to do is set a style inside an element in the react component which is "width: xx%" and the animate it from 0% to xx%. Since the element when rendered already has this property the animation is not working. I've looked into the "ReactCSSTransitionGroup" but did not come closer to a solution. I started messing around with setTimeOut to set the style attribute after the component was rendered but it felt really messy and "hackish". Could someone point me in the right direction?

If you are trying to animate the component after it has been rendered (from 0 to n%) you can do it by calling setState in componentDidMount. As browsers are not rerendering stuff that has changed in the same animation frame but merge changes and render the end result, you'll need to wrap it in requestAnimationFrame
I explained it throughly in this blog post.
Code will look like this:
export default class AnimateMe extends Component {
state = {
width: 0
};
componentDidMount() {
requestAnimationFrame(() => {
this.setState({ width: "75%" });
});
}
render() {
return (
<div style={{ width: this.state.width }}>
Animate my width
</div>
);
}
}
I made a working example:
https://codesandbox.io/s/7z1j794oy1
Hope that helps!

Related

How to properly make animation/transition in react.js

I want to smoothly resize a DIV with onClick event. But transition doesn't work. onClick just changes the style without animation.
App.js
import React, { useState } from 'react'
import './App.scss';
function App() {
const [clicked, setClicked] = useState(-1)
return (
<div
className={clicked === -1 ? "app" : "app__clicked"}
onClick={() => setClicked(0)}>
div clicked {clicked}
</div>
);
}
export default App;
App.scss
.app {
background-color: red;
transition: width 3s;
&__clicked {
background-color: blue;
width: 100px;
}
}
I think I'm doing something wrong with SCSS.
As can be seen here, your SASS rules will result in two different css classes which you toggle between when assigning a className prop to your div.
The second class is app__clicked and it has no transition property which is why the transition doesn't work. It also doesn't work because, as indicated in the comments, you don't have an initial width on the div, so there is nothing to transition between. By moving the transition property to the app_clicked class and setting width to 100% in the initial state, you will have a working example.
As an advice when doing transitions manually, use a base class which has the transition property set and then toggle the other state by means of other classes (or inline with style) to make sure that the element always has the transition property set. Like this:
<div className={ `app ${clicked === -1 ? "before" : "after"}`}>
div clicked {clicked}
</div>
or
<div className={ "app" } style={{"width": clicked === -1 ? "100%" : "100px"}}>
div clicked {clicked}
</div>
Finally, you might wanna have a look at react-transition-group where transitions with React components is shown. However, you might think that this brings nothing new to the table and that it is too verbose. But it's good to know about and it might have its use cases.
Here is a sandbox with all of the above examples and an example with the CSSTransition component from react-transition-group: Sandbox

How do I get a CSS transition to apply to styles dynamically generated by React?

I have a button component that makes use of a theme provided by a context:
Button.js
() => {
const theme = useContext(themeContext); // { primaryColor: "blue" }
return <button className="MyButton" styles={{ backgroundColor: theme.primaryColor }}>Hello</button>
}
Button.styles.scss
.MyButton {
background-color: purple
transition: background-color 0.1s
&:hover {
background-color: green
}
}
Since the background color is now being set by React, the transition effect no longer works. Is there a way to get this to work without, for example, rewriting everything in JSS (given that all the app's styling is done in scss).
Did you verify that the React theme isn't setting transition and hover rules? If it is, then the only way to override those is to set the styles inline. Perhaps add onto the theme object (or a clone of it) before assigning in the styles attr, or somehow overlay the theme nearer to its source.

Possible to use CSS transitions with textarea rows value?

In all the years I've been developing websites this situation has never cropped up before and I'm not sure that what I'm attempting to do is even possible.
I have a React component with a textarea. It's initial state is rendered with a height of 1 row like this :
state = {
rows: 1
}
...
<textarea
...
rows={this.state.rows ? this.state.rows : 1}
onFocus={this.onFocus}
...
/>
The onFocus function changes the rows state to 5, thereby expanding the textarea.
This works perfectly, but I'm now trying to add CSS transitions to the textarea so it expands nicely instead of just instantly expanding.
Everything I've tried doesn't work, for example :
textarea#content {
transition: all 2s ease-in-out;
}
...so my question is - is it not possible to use CSS transitions in this way? I did some googling and couldn't find any answers which leads me to believe that it isn't, but I just want to make sure before I set about achieving this another way.
Can't say how React might be involved here, but for a transition to work, the CSS property being transitioned must have a default value set for it. You are indirectly affecting the height property by changing the rows, but you are not actually specifying that you want the height to change, so you can't transition the height if you are only indirectly changing it. Also, there is no CSS rows property, so no luck on transitioning that either.
The solution is to not set the height indirectly with rows in the first place. Set the height directly and set a default value for height in the CSS.
And, you really don't even need JavaScript to do this:
textarea {
height:1em; /* Initial value required for transitions to work */
transition:height 1s ease-in-out; /* configure the transition*/
}
/* Style to be applied automatically when the textarea recievs the focus */
textarea:focus {
height:5em; /* A change in this property will trigger the transition */
}
<textarea></textarea>

Transition component Vuejs - Not working - Differences between inner and outer

EDIT Simplify the question
http://jsfiddle.net/bf830qoq/
Why the transition in that minimalist example does not work? (It mimics the real case in my code)
Former post
I would like to apply a transition on a custom component in VueJs 2, depending on v-if condition.
I tried to put the transition inner the component loading :
Parent component
<loading v-if="shared.loading"></loading>
Loading.vue
<template>
<transition name="slide-fade">
<div class="loading-container">
<div class="container-no-text">
<div class="title-no">Loading</div>
</div>
</div>
</transition>
</template>
<script>
import Store from '../store.js'
export default{
data () {
return {
shared: Store.state,
}
},
}
</script>
<style>
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for <2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
</style>
It simply does not work, the login disappears without any animation.
I tried to mimic the situation with JSFiddle :
Outer transition : http://jsfiddle.net/0v0wyLv0/ WORKING
Inner transition : http://jsfiddle.net/jpcays2b/ NOT WORKING
Here are the questions:
Why the second JSFiddle does not work (the inner one)?
Why on my code the "outer" does not work?
How can I make the loading component disappear smoothly?
Example which is working
https://jsfiddle.net/er3tjyh0/
Thank you
As par the implementation of transition in vue.js, transition wrapper component allows you to add entering/leaving transitions for any element or component in the following contexts:
Conditional rendering (using v-if)
Conditional display (using v-show)
Dynamic components
Component root nodes
From the docs:
When an element wrapped in a transition component is inserted or removed, this is what happens:
Vue will automatically sniff whether the target element has CSS transitions or animations applied. If it does, CSS transition classes will be added/removed at appropriate timings.
If the transition component provided JavaScript hooks, these hooks will be called at appropriate timings.
If no CSS transitions/animations are detected and no JavaScript hooks are provided, the DOM operations for insertion and/or removal will be executed immediately on next frame (Note: this is a browser animation frame, different from Vue’s concept of nextTick).
That's why transition will only work, when it is wrapping the v-if and not when it is inside, thats how it is implemented.

I want my function to be triggered when the route changes

I have a function that changes the css of a class and I want that function to be called anytime that the route changes. I also want this logic to be placed inside the ApplicationView so it will be called anywhere at anytime the route changes.
The class that is being altered by the function (we'll call that class .float-right-col) is created once on every .hbs template in my app.
<div class="float-right-col">
</div>
The pseudo code of what I want
Whenever we are transitioned to a new route {
Set the css of float-right-col to this by toggle classes with overriding attributes
}
Information that I left out for simplicity's sake (optional) AKA The Big Picture:
Eventually the pseudo code mentioned above will have another condition && that requires the screen to be > 800px.
Whenever we are transitioned to a new route {
check if the screen size is below 800px & if it is {
Set the css of float-right-col to this
}
}
Ideally the css would just know the screen size and adjust the css before the page loads.
With this pseudo code above, the page will load with the default css, and then the function will be called which makes float-right-col transition into a new position.
To toggle the css of this element i add and remove these two classes to .float-right-col.
.openCol {
position:absolute;
right: 0px;
transition: all .2s ease 0s;
}
.closeCol {
position:fixed;
right: -290px;
transition: all .2s ease 0s;
}
I've also tried using .css()
Finally, I've tried media queries, but those seem to only work on the initial load of the first page
#media screen and (max-width: 800px) {
.float-right-col {
position: fixed !important;
right: -290px;
}
}
You could observe the currentPath in the ApplicationController and react on any changes.
App.ApplicationController = Ember.Controller.extend({
currentPathChanged: function() {
console.log(this.get('currentPath'));
}.observes('currentPath')
});

Categories