EzDev.org

react-motion

react-motion - A spring that solves your animation problems.


React Motion CSS transform from center

I am using react-motion for CSS transfrom in react. this bellow code scales my desired output from top left corner.

    <Motion defaultStyle={{ x: 0 }} style={{ x: spring(360) }} >
    {value => {return <div style={{
      width: value.x,
      height: value.x,
      animation: `scale 5s infinite`,
      transform: `scale(1,1)`,
    }}
    > <this.ComponentName post={post} view={view}/></div>}}
  </Motion>

How can i make it scale from center?


Source: (StackOverflow)

React - animate mount and unmount of a single component

Something this simple should be easily accomplished, yet I'm pulling my hair out over how complicated it is.

All I want to do is animate the mounting & unmounting of a React component, that's it. Here's what I've tried so far and why each solution won't work:

  1. ReactCSSTransitionGroup - I'm not using CSS classes at all, it's all JS styles, so this won't work.
  2. ReactTransitionGroup - This lower level API is great, but it requires you to use a callback when the animation is complete, so just using CSS transitions won't work here. There are always animation libraries, which leads to the next point:
  3. GreenSock - The licensing is too restrictive for business use IMO.
  4. React Motion - This seems great, but TransitionMotion is extremely confusing and overly complicated for what I need.
  5. Of course I can just do trickery like Material UI does, where the elements are rendered but remain hidden (left: -10000px) but I'd rather not go that route. I consider it hacky, and I want my components to unmount so they clean up and are not cluttering up the DOM.

I want something that's easy to implement. On mount, animate a set of styles; on unmount, animate the same (or another) set of styles. Done. It also has to be high performance on multiple platforms.

I've hit a brick wall here. If I'm missing something and there's an easy way to do this, let me know.


Source: (StackOverflow)

How to use React TransitionMotion willEnter()

Using React Motion's TransitionMotion, I want to animate 1 or more boxes in and out. When a box enters the view, it's width and height should go from 0 pixels to 200 pixels and it's opacity should go from 0 to 1. When the box leaves the view, the reverse should happen (width/height = 0, opacity = 0)

I have tried to solve this problem here http://codepen.io/danijel/pen/RaboxO but my code is unable to transition the box in correctly. The box's style jumps immediately to a width/height of 200 pixels instead of transitioning in.

What is wrong with the code?

let Motion = ReactMotion.Motion
let TransitionMotion = ReactMotion.TransitionMotion
let spring = ReactMotion.spring
let presets = ReactMotion.presets

const Demo = React.createClass({
  getInitialState() {
    return {
      items: []
    }
  },
  componentDidMount() {

    let ctr = 0

    setInterval(() => {
      ctr++
      console.log(ctr)
      if (ctr % 2 == 0) {
        this.setState({
          items: [{key: 'b', width: 200, height: 200, opacity: 1}], // fade box in
        });
      } else {
        this.setState({
          items: [], // fade box out
        });
      }

    }, 1000)
  },
  willLeave() {
    // triggered when c's gone. Keeping c until its width/height reach 0.
    return {width: spring(0), height: spring(0), opacity: spring(0)};
  },

  willEnter() {
    return {width: 0, height: 0, opacity: 1};
  },

  render() {
    return (
      <TransitionMotion
        willEnter={this.willEnter}
        willLeave={this.willLeave}
        defaultStyles={this.state.items.map(item => ({
          key: item.key,
          style: {
            width: 0, 
            height: 0,
            opacity: 0
          },
        }))}
        styles={this.state.items.map(item => ({
          key: item.key,
          style: {
            width: item.width, 
            height: item.height,
            opacity: item.opacity
          },
        }))}
        >
        {interpolatedStyles =>
          <div>
            {interpolatedStyles.map(config => {
              return <div key={config.key} style={{...config.style, backgroundColor: 'yellow'}}>
                <div className="label">{config.style.width}</div>
              </div>
            })}
          </div>
        }
      </TransitionMotion>
    );
  },
});

ReactDOM.render(<Demo />, document.getElementById('app'));

Source: (StackOverflow)

How to add unmounting animation with React Motion?

I want to add unmounting animation with React-Motion, but I can't found any information about that. This is my code:

{this.state.uploading ? (
    <Motion defaultStyle={{ top: 0 }} style={{ top: spring(-150) }}>
    {
        interpolatingStyle => {
            return (<UploadList style={interpolatingStyle} files={uploadingFiles}/>);
        }
    }
    </Motion>
) : ''}

animation perfectly working on mounting, but on unmount, it just disappears. Is there a way to fix this?


Source: (StackOverflow)

React-motion mobile wep performance is too low

I'm creating website with React + React-Router. I used react-router-transition to animate on switching views, and used React-motion-ui-pack to animate for little components.

The problem is when I tested on Desktop PC, animation is fine, but tested on mobile browser, it causes much lags.

As I know, react-router-transition and react-motion-ui-pack both using React-Motion. When I added animation with CSS3 Transforms, it does not worked, so I used just CSS properties directly(like using top/left instead of translate transforms).

This is part of my code:

export default class App extends React.Component {
    render() {
        return (
            <div id="App">
                <TopBar />
                <GlobalNav />

                <RouteTransition
                    pathname={this.props.location.pathname}
                    atEnter={{ opacity: 0.0 }}
                    atLeave={{ opacity: 1.0 }}
                    atActive={{ opacity: 1.0 }}>
                    <div id="views">
                        {this.props.children}
                    </div>
                </RouteTransition>

                <Footer />
            </div>
        );
    }
}

As you can see, I modified opacity onEnter and onLeave. But this causes so much low performance on the mobile devices.

Is there a way to solve this problem?


Source: (StackOverflow)

Restart animation on state/props change in react-motion

I am trying to animate breadcrumbs using react-motion from x: -20 to x: 0.

Folder > SubFolder > Child

The issue is, the breadcrumbs animate perfectly on the first render. Subsequently when the props or even state changes, the animations are not updated. This seems to be a known bug.

My question is, how do I "restart" animation on state/prop changes?

const getDefaultStyles = crumbs => {
  const defaultStyles = crumbs.map(() => ({x: -20}))
  console.log(defaultStyles)
  return defaultStyles
}

const getStyles = previousInterpolatedStyles => {
  return previousInterpolatedStyles.map((_, i) => {
    return i === 0 ? {x: spring(0)} : {x: spring(previousInterpolatedStyles[i-1].x)}
  })
}

const Breadcrumb = ({ crumbs }) => (
  <div className='breadcrumb-container'>

      <StaggeredMotion
        defaultStyles={getDefaultStyles(crumbs)}
        styles={getStyles}>
        {
          interpolatedStyles =>
            <div className='breadcrumb-list'>
              {
                interpolatedStyles.map(({x}, i) =>
                  <div className='breadcrumb' key={i} style={{
                      WebkitTransform: `translate3d(${x}px, 0, 0)`,
                      transform: `translate3d(${x}px, 0, 0)`
                    }}>
                    <a rel='nofollow' href='#'>Title</a>                    
                  </div>
                )
              }
            </div>

        }
      </StaggeredMotion>

  </div>
)

Source: (StackOverflow)

Animating exit of an element in React Motion (which receives these elements from a parent component)

Background I am trying to create a container for a collection of elements, each of which can be removed from the collection. When an element is removed, I want to animate its exit, and I am trying to achieve this using React Motion.

Here's a diagram of the above:

enter image description here

Problem I thought of using React Motion's TransitionMotion component, and got stuck trying to write a function that needs to be passed to it. Here is my — incorrect — code:

class Container extends Component {

  state = {
    elementStyles: {}
  }

  componentDidMount() {
    this.getElementStyles();
  }

  componentDidUpdate() {
    this.getElementStyles();
  }

  getElementStyles() {
    if (!this.props.children.length || this.hasElementStyles()) return;

    // this assumes all elements passed to the container are of equal dimensions
    let firstChild = this.refs.scroller.firstChild;

    let elementStyles = {
      width: firstChild.offsetWidth,
      height: firstChild.offsetHeight,
      opacity: 1
    };

    this.setState({
      elementStyles
    });
  }


  hasElementStyles() {
    return !isEmpty(this.state.elementStyles); // lodash to the rescue
  }

  willLeave() {
    return { width: spring(0), height: spring(0), opacity: spring(0) }
  }

  getChildrenArray() {
    return Children.toArray(this.props.children); // that's React's util function
  }

  getModifiedChild(element, props) {
    if (!element) return;

    return React.cloneElement(
      element,
      {style: props.style}
    );
  }

  getInitialTransitionStyles() {
    let elements = this.getChildrenArray();
    let result = elements.map((element, index) => ({
      key: element.key,
      style: this.state.elementStyles
    }));
    return result;
  }

  render() {
    if (this.hasElementStyles()) {

      return (
        <TransitionMotion
          willLeave={this.willLeave}
          styles={this.getInitialTransitionStyles()}
        >
            { interpolatedStyles => {
              let children = this.getChildrenArray();
              return <div ref="scroller" className="container">
                { interpolatedStyles.map((style, index) => {
                    return this.getModifiedChild(children[index], style);
                  })
                }
              </div>
            }}
        </TransitionMotion>
      );
    } else {
      return (
        <div ref="scroller" className="container">
          { this.props.children }
        </div>
      );
    }
  }

}

Notice this line inside the map function in the TransitionMotion component: return this.getModifiedChild(children[index], style). It is wrong, because once an element is removed from the collection, this.props.children will change, and indices of the children array will no longer correspond to the indices of the styles array calculated from those children.

So I what I need is either some clever way to track the props.children before and after an element has been removed from the collection (and I can't think of one; the best I could come up with was using a find function on the array return this.getModifiedChild(children.find(child => child.key === style.key), style);, but that will result in so many loops within loops I am scared even to think about it), or to use some completely different approach, which I am not aware of. Could you please help?


Source: (StackOverflow)

Unable to animate React-Konva Circle using React-Motion

I am using React-Konva to draw shapes in my app. I have drawn a circle inside another circle and grouped them. Now, what I want to do is that on a button click the circles should animate (move horizontally). Here is my related code:

<Layer>
  <Motion style={{a: spring(open ? 400 : x)}}>
    {({a}) => {
      return(
        <div
          style={{
            WebkitTransform: `translate3d(${a}px, 0, 0)`,
            transform: `translate3d(${a}px, 0, 0)`,
          }}
        >
          <Group draggable={true}>
            <CircleComponent
              x={parseInt(x)}
              y={parseInt(y)}
              radius={parseInt(radius)}
              color={color}
              shadowValue={parseInt(shadowValue)}
            />
            <CircleComponent
              x={parseInt(x)}
              y={parseInt(y)}
              radius={parseInt(innerRadius)}
              color={innerColor}
            />
          </Group>
        </div>
      );}
    }
  </Motion>
</Layer>

Right now I am getting this error: 'Cannot read property '_idCounter' of undefined'. And this is because I'm introducing a div container inside Layer tag. But if I remove the div container and apply the transform styling to the Group tag, nothing happens. I have read the docs and the Group class doesn't accept any style props. Is there any workaround?


Source: (StackOverflow)

On react-motion, how to reset an animation?

In a certain UI a person can update an image, whenever they upload a new image I want the previous one to fade into the new one. The problem is that the animation runs only for the first change:

return(
  <div>
   <Motion defaultStyle={{opacity: 1}} style={{opacity: spring(0)}}>
     { interpolatedStyle => <img style={interpolatedStyle} src={this.previousSrc/> }
   </Motion>
   <img src={this.props.src} />
  </div>
)

I have a component with two <img> inside it, one to display the previous image and another one to display the next. I'm using <Motion> and spring to change the opacity of the old image, the problem is that the animation only runs once, the second time the user updates the image the old image is always invisible already.

How do I reset the animation for every render?


Source: (StackOverflow)

react animation on img src change from an array

I have this react code that changes the img src onClick, it gets the new img src from an array, I now want to add an animation to it using react-motion, Everytime the img src changes I want to play the animation so far I got it working threw a ? statement however it only plays every other time it changes I think its very similar to what Im doing. here is the code:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchPosts } from '../actions/index';
import { Link } from 'react-router';

export default class HomePage extends Component {
    constructor() {
        this.state = { index : 0 };
        this.blogPostImages = ['./img/placeholder.jpg', './img/placeholderB.jpg', './img/placeholderC.png'];
    }

    changeBlogPicForwards() {
        let i = this.state.index;
        if (i == this.blogPostImages.length - 1) {
            i = 0; 
        } else {
            i = i + 1; 
        }
        this.setState({index: i});
    }

    changeBlogPicBackwards() {
        let i = this.state.index;
        if (i == 0) {
            i = this.blogPostImages.length - 1; 
        } else {
            i = i - 1;
        }
        this.setState({index: i});
    }

    render() {
        var blogCurrentPic = this.blogPostImages[this.state.index];

        return (
            <div>
                <div className="top-section-actions">
                           <Motion style={{ x: spring( this.state.index ? 1:0 ) }}>
                            {({ x }) =>
                                <div className="image-holder">
                                    <img className="blog-pictures" src={blogCurrentPic} style={{
                                        WebkitTransform: `translate3d(${x}px, 0, 0)`,
                                        transform: `scale(${x}, ${x})`,
                                    }} />
                                </div>
                            }
                        </Motion>
                    <div className="blog-name">
                        <div className="left-arrow-action arrow-icons">
                            <i onClick={(e) => this.changeBlogPicForwards(e)} className="fa fa-arrow-circle-o-left fa-2x" aria-hidden="true"></i>
                        </div>
                        <div className="right-arrow-action arrow-icons">
                            <i onClick={(e) => this.changeBlogPicBackwards(e)} className="fa fa-arrow-circle-o-right fa-2x" aria-hidden="true"></i>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

The type of animation I want does not matter since Im just trying to play any animation after the img src changes,


Source: (StackOverflow)

Any concrete example about how to use react-motion for SVG path with D3?

All:

I am pretty new to React-Motion, most examples on its github is about how to interpolate single number, I wonder I want to apply a array of data objects to it, how can I implement this?

My use case is to implement same effect of transition from D3 for svg path

I am thinking something like:

<Transition data={data}>
    {
        (interpolateData)=> {
             return <path d={interpolateData} />
        }
    }
</Transition>

Thanks


Source: (StackOverflow)

React motion: animation on hover gets laggy after multiple times

I'm quite new to React and all the fancy stuff.

On google-react-map, there's a few markers. Each of them have an Icon I want to scale on hover.

I use styled-components for styling

const Icon = styled.div`
  width: ${MARKER_SIZE}px;
  height: ${MARKER_SIZE}px;
  /* animated */
  transform: scale(${props => props.scale});
`;

with react-motion

<Motion defaultStyle={{ scale: 1 }} style={{ scale: spring($hover ? 1.5 : 1) }}>
  { interpolated =>
    <Icon $hover={$hover} onClick={this.handleClick} {...interpolated}/>
  }
</Motion>

That works smooth and fast at start but after a few hover, animation gets more and more laggy.

I probably miss something crucial here


Source: (StackOverflow)

React Router v4 Match transitions using React Motion

I'm loving RR4 and RM, there's already great examples for React Router V4 (https://github.com/ReactTraining/react-router/tree/v4/website/examples) but i'm struggling to understand how I can use the new V4 API to transition between different Matches in my Router with React Motion, fading in and out between my 'pages'.

I've tried to understand how the Transition example works with the MatchWithFade but I'm missing how to take this and apply it to multiple matches representing my page structure.

As an example: given two routes setup in my Router how can I have the mounting and unmounting handled by react-motion with TransitionMotion?

<Router>
  <div>
    <Match pattern="/products" component={Products} />
    <Match pattern="/accessories" component={Accessories} />
  </div>
</Router>

Any help would be greatly appreciated.


Source: (StackOverflow)

React Motion willEnter and willLeave not firing

I am trying to get react-motion up and running but for some reason the methods willEnter and willLeave don't seem to be firing when using TransitionMotion.

Currently my setup is as follows:

import React, { Component } from 'react';
import RecommendationItem from '../typeahead/typeahead_recommendation_block';
import { TransitionMotion, spring } from 'react-motion';

const CALIBRATE = { stiffness: 120, damping: 14 };

export default class Recommendations extends Component {

constructor(props) {
  super(props);

  this.willEnter = this.willEnter.bind( this );
  this.willLeave = this.willLeave.bind( this );
  this.getStyles = this.getStyles.bind( this );
}

willEnter() {
  console.log( 'Enter' );
  return {
    maxHeight :0,
    opacity: 0
  }
}

willLeave(){
  console.log( 'Leave' );
  return {
    maxHeight : spring(0, CALIBRATE),
    opacity: spring(0, CALIBRATE)
  }
}

getStyles() {
  return {
    maxHeight: spring(500, CALIBRATE),
    opacity: spring(1, CALIBRATE)
  }
}

render() {
  const {
    showRecommendations
  } = this.props

  if( !showRecommendations ) {
    return null;
  }

  return (
    <div className="typeahead-recommendations">
      <TransitionMotion
        willEnter={ this.willEnter }
        willLeave={ this.willLeave }
        styles={
          Object.keys( this.props.recommendations ).map( ( key, i ) => ({
            key : `${key}-${i}`,
            data : {
              title           : key,
              recommendations : this.props.recommendations[key]
            },
            style : this.getStyles()
          }))
        }>
        { (interpolate) =>
          <div>
            {
              interpolate.map(block => {
                if( block.data.recommendations.length && block.key !== 'productSuggestions' ) {
                  return  <div key={ block.key } style={ block.style }>
                            <RecommendationItem
                              title={ block.data.title }
                              recommendations={ block.data.recommendations } />
                          </div>
                }
              })
            }
          </div>
        }
      </TransitionMotion>
    </div>
  )
}
}

Recommendations.displayName = "Recommendations";

At the moment the console.logs in willEnter and willLeave are simply never firing. Any advice on why this might be would be much appreciated


Source: (StackOverflow)

can't get TransitionMotion to work in React Motion

I'm trying to render a set of data (this.props.data) in React with mount/unmount animation using react-motion TransitionMotion and spring. This data is being updated from a separate component, via a search/filter function. I tried my best to follow the API reference, but console debug is still throwing me this warning: Failed prop type: Invalid prop `styles` supplied to `TransitionMotion`.

Despite this warning, the data still manages to render. There are no mount/unmount transitions, and even if I'm just rendering 10 items max, the entire tab lags like hell when I change the contents of this.props.data.

Does anyone know what funky thing is going on with my code? Any help with debugging is appreciated.

import React, { Component } from "react";

import classNames from "classnames";
import { TransitionMotion, spring } from "react-motion";

import QtlPanel from "../QtlPanel.jsx";
import GenePanel from "../GenePanel.jsx";
import Loader from "./Loader.jsx";

class PanelArea extends Component {
  getDefaultStyles = () => {
    return this.props.data.map( item => ({
      key: item.id.toString(),
      data: item,
      style: {
        height: 0,
        opacity: 1
      }
    }) );
  }

  getStyles = () => {
    return this.props.data.map( item => ({
      key: item.id.toString(),
      data: item,
      style: {
        height: spring(80),
        opacity: spring(1)
      }
    }) );
  }

  willEnter = () => ({
    height: spring(0),
    opacity: spring(1)
  })

  willLeave = () => ({
    height: spring(0),
    opacity: spring(0)
  })

  render() {
    const classes = classNames(
      "panel-area", {
        "loading": this.props.loading
      }
    );

    const transitionProps = {
      defaultStyles: this.getDefaultStyles(),
      styles: this.getStyles(),
      willEnter: this.willEnter,
      willLeave: this.willLeave
    };

    return (
      <div className={classes}>
        <Loader isLoading={ this.props.loading } />
        <TransitionMotion { ...transitionProps }>
          { styles => (
            <div>
              { styles.map(({ key, style, data }) => {
                const panelProps = {
                  key: key,
                  data: data,
                  style: style
                };

                if (this.props.activeDataset === "qtl") {
                  return <QtlPanel { ...panelProps } />;
                } else {
                  return <GenePanel { ...panelProps } />;
                }
              }) }
            </div>
          ) }
        </TransitionMotion>
      </div>
    );
  }
}

export default PanelArea;

Source: (StackOverflow)