Respond to a smooth transition between different states in a component

I have a simple component:

var component = React.createClass({ render: function(){ if (this.props.isCollapsed){ return this.renderCollapsed(); } return this.renderActive() }, renderActive: function(){ return ( <div> ... </div> ); }, renderCollapsed: function(){ return ( <div> ... </div> ); }, }); 

Basically, when a property changes, the component will either show the state of the active state or the state of crash.

I think that when a change of properties occurs, that is, active β†’ collapse, or vice versa, I want the old view to β€œshrink” or β€œexpand” smoothly to show the new view. For example, if it is active β†’ Minimize, I want the active user interface to shrink to the size of the user interface with collapse and display it smoothly.

I am not sure how to achieve this effect. Please share some ideas. Thank you

+5
source share
7 answers

Instead of conditionally displaying two different final states of the components, you could instead
switch the class to the same component. You can have active and collapsed classes as follows:

For instance:

 .active{ -webkit-transition: -webkit-transform .5s linear; // transition of // 0.5 of a second height: 200px; } .collapsed{ height: 0px; } 

See this resource for examples.

+5
source

The standard way is to use CSSTransitionGroup from react-transition-group , which is pretty simple. Wrap the component with CSSTransitionGroup and set timeouts for input and output, for example:

 <CSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}> {items} </CSSTransitionGroup> 

From v1-stable docs :

"In this component, when a new element is added to the CSSTransitionGroup, it will receive an example-enter CSS class and an example-input-active CSS class is added to the next tick."

Add style to your CSS classes to get the right animation.

There's also a pretty good explanation in React docs , check it out.

There are third-party components for animation.

+3
source

Here is a minimal working example:

 const collapsible = ({active, toggle}) => <div> <button type="button" onClick={toggle}>Toggle</button> <div className={'collapsible' + (active? ' active': '')}> text </div> </div> const component = React.createClass({ getInitialState() { return {active: false} }, toggle() { this.setState({active: !this.state.active}) }, render() { return collapsible({active: this.state.active, toggle: this.toggle}) } }) ReactDOM.render(React.createElement(component), document.querySelector('#root')) 
 .collapsible { height: 1.5rem; transition: height 0.25s linear; background: #333; border-radius: 0.25rem } .collapsible.active { height: 7rem } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script> <div id="root"></div> 

The view can be β€œshrink” or β€œexpand” smoothly through the CSS transition , which is triggered by changing the CSS properties.

To manage CSS properties using React, we can display state changes in property values ​​or className in render() .

In this example, the .active class affects the height value and is controlled by state.active . The class is switched using React in response to state changes and triggers a CSS transition.

For smoother transitions, see this article .

+2
source

Another approach to this situation may be to change state after the animation is complete. The advantages of this are that you can apply not only transitions, but also any actions you want (js-animation, smile, etc.), the main thing is to remember to call the end callback;)

Here is a working example of CodePen

And here is a sample code:

 const runTransition = (node, {property = 'opacity', from, to, duration = 600, post = ''}, end) => { const dif = to - from; const start = Date.now(); const animate = ()=>{ const step = Date.now() - start; if (step >= duration) { node.style[property] = to + post; return typeof end == 'function' && end(); } const val =from + (dif * (step/duration)); node.style[property] = val + post; requestAnimationFrame(animate); } requestAnimationFrame(animate); } class Comp extends React.Component { constructor(props) { super(props); this.state = { isCollapsed: false } this.onclick = (e)=>{ this.hide(e.currentTarget,()=>{ this.setState({isCollapsed: !this.state.isCollapsed}) }); }; this.refF = (n)=>{ n && this.show(n); }; } render() { if (this.state.isCollapsed){ return this.renderCollapsed(); } return this.renderActive() } renderCollapsed() { return ( <div key='b' style={{opacity: 0}} ref={this.refF} className={`b`} onClick={this.onclick}> <h2>I'm Collapsed</h2> </div> ) } renderActive() { return ( <div key='a' style={{opacity: 0}} ref={this.refF} className={`a`} onClick={this.onclick}> <h2>I'm Active</h2> </div> ) } show(node, cb) { runTransition(node, {from: 0, to: 1}, cb); } hide(node, cb) { runTransition(node, {from: 1, to: 0}, cb); } } ReactDOM.render(<Comp />, document.getElementById('content')); 

And, of course, for this approach to work, your only opportunity is to relay the state, not the Component attribute, which you can always set in the componentWillReceiveProps method if you have to deal with them.

Update

The Codepen link has been updated with a clearer example that shows the benefits of this approach. The transition has been changed to javascript animation without relying on the transition event.

+2
source

You can add a class that describes the active state, i.e. .active and switch this class when switching states.

Css should look something like this:

 .your-component-name{ // inactive css styling here } .your-component-name.active { // active css styling here } 
+1
source

As you want to display two different components for each of the active and collapsed, wrap them in a div that controls the height using CSS.

 render: function(){ var cls = this.props.isCollapsed() ? 'collapsed' : 'expanded'; return( <div className={cls + ' wrapper'}> { this.props.isCollapsed() ? this.renderCollapsed() : this.renderActive() } </div> ); } 

and in your CSS:

 .wrapper{ transition: transform .5s linear; } .expanded{ height: 200px; } .collapsed{ height: 20px; } 
+1
source

Here you have the Toggle response component using the Velocity-React library, which is great for transferring animations to React uis:

 import React, { Component } from 'react'; import { VelocityTransitionGroup } from 'velocity-react'; export default class ToggleContainer extends Component { constructor () { super(); this.renderContent = this.renderContent.bind(this); } renderContent () { if (this.props.show) { return ( <div className="toggle-container-container"> {this.props.children} </div> ); } return null } render () { return ( <div> <h2 className="toggle-container-title" onClick={this.props.toggle}>{this.props.title}</h2> <VelocityTransitionGroup component="div" enter="slideDown" leave="slideUp"> {this.renderContent()} </VelocityTransitionGroup> </div> ); } }; ToggleContainer.propTypes = { show: React.PropTypes.bool, title: React.PropTypes.string.isRequired, toggle: React.PropTypes.func.isRequired, }; 

Hope this helps!

0
source

Source: https://habr.com/ru/post/1260961/


All Articles