joshwcomeau / react-flip-move

Effortless animation between DOM changes (eg. list reordering) using the FLIP technique.
http://joshwcomeau.github.io/react-flip-move/examples
MIT License
4.09k stars 258 forks source link

Animations not rendering, array items have unique keys #147

Closed JellyKid closed 7 years ago

JellyKid commented 7 years ago

I can see positions clearly switch but no animations happen and no classes are applied. Is there something I can do to debug this?

import React from 'react';
import { Table } from 'react-bootstrap';
import FlipMove from 'react-flip-move';

export default class Rankings extends React.Component {
  constructor(props) {
    super(props);
  }

  render(){

    if(!this.props.totals || !this.props.players || !this.props.player){
      return null;
    }

    let rank = 0;
    let lastValue = 0;
    const statRows = this.props.totals
    .sort((a,b) => b.value - a.value)
    .map(
      (total) => {
        if(total.value != lastValue){rank++;}
        let style = total.player._id === this.props.player._id ? 'highlight-row' : '';
        let row = (
          <tr key={total._id} className={style}>
            <td>{rank}</td>
            <td>{`${total.player.firstName} ${total.player.lastName.charAt(0)}`}</td>
            <td>{total.player.initials}</td>
            <td>{total.value}</td>
          </tr>
        );
        lastValue = total.value;
        return row;
      }
    );

    return (
      <div>
        <h2>Rankings</h2>
        <Table className='table-common' >
          <thead>
            <tr>
              <th>#</th>
              <th>Player</th>
              <th>Initials</th>
              <th>Points</th>
            </tr>
          </thead>

          <FlipMove
            typeName='tbody'
            duration={750}
            enterAnimation="elevator"
            leaveAnimation="elevator"
            easing='easing-out'>
            {statRows}
          </FlipMove>

        </Table>
      </div>
    );
  }
}
JellyKid commented 7 years ago

array

I decided to try and log "statRows" right before the render function and I can see array elem 0 and 1 flip but no animation. Stupid question, but do I need to install the CSS separately?

joshwcomeau commented 7 years ago

Hey there,

So, I think the issue is the tables.

FlipMove works by setting transform: translate on the node to artificially position it. AFAIK you can't use transition on <tr> or <td> nodes.

The solution in this case would be to use <div> (or similar block containers). Which is kind of a lame answer, I know, since <table> may be the most semantic way to mark up your code. Unfortunately I don't think there's much I can do.

(You can try using display: table to emulate table layouts, but it may have exactly the same issue)

JellyKid commented 7 years ago

So I made everything a <div> and I'm still not seeing the animation. Maybe react is re-rendering <FlipMove /> for some reason.... IDK. If there is anything else you would like me to try let me know.

divs

import React from 'react';
import { Table } from 'react-bootstrap';
import FlipMove from 'react-flip-move';

export default class Rankings extends React.Component {
  constructor(props) {
    super(props);
  }

  render(){

    if(!this.props.totals || !this.props.players || !this.props.player){
      return null;
    }

    let rank = 0;
    let lastValue = 0;
    const statRows = this.props.totals
    .sort((a,b) => b.value - a.value)
    .map(
      (total) => {
        if(total.value != lastValue){rank++;}
        let style = total.player._id === this.props.player._id ? 'highlight-row' : '';
        let row = (
          <div key={total._id} className={style} >
            <div >{rank}</div>
            <div >{`${total.player.firstName} ${total.player.lastName.charAt(0)}`}</div>
            <div >{total.player.initials}</div>
            <div >{total.value}</div>
          </div>
        );
        lastValue = total.value;
        return row;
      }
    );

    console.log(statRows);

    return (
      <div>
        <h2>Rankings</h2>

        <div>

          <div >
            <div >#</div>
            <div >Player</div>
            <div >Initials</div>
            <div >Points</div>
          </div>

          <FlipMove
            // typeName='div'
            duration={1000}
            enterAnimation="elevator"
            leaveAnimation="elevator"
            easing='easing-out'>
            {statRows}
          </FlipMove>
        </div>
      </div>
    );
  }
}
joshwcomeau commented 7 years ago

Hmmm... Weird.

Off the top of my head, everything looks right. It looks like there are some console errors in that screenshot, could they be related?

If not, I'd try simplifying it until it works. What if you do this:

          <FlipMove
            // typeName='div'
            duration={1000}
            enterAnimation="elevator"
            leaveAnimation="elevator"
            easing='easing-out'>
              <div key="a">Foo</div>
              <div key="b">Bar</div>
          </FlipMove>

If this works (and it really should), then I'd incrementally move towards what you have now. If you can find the exact change that breaks it, I should be able to help :)

JellyKid commented 7 years ago

easing='ease-out' not easing='easing-out'

Boy do I feel dumb, that took me way longer than it should have to figure out. Sorry to have wasted your time. I didn't see an error about having an incorrect easing prop so maybe that would have helped but the fault is all mine on that one.

joshwcomeau commented 7 years ago

No worries! I didn't catch it either. Happens to us all, haha.

Sucks when the answer is right in front of you but you miss it.

As for a warning when an invalid easing is specified... Can definitely see how that'd be helpful. The only reason I'd hesitate is that Flip Move isn't really concerned with that, I delegate whatever you provide to CSS and CSS decides if it's valid or not. Plus then I'd have to validate what is/isn't kosher cubic-beziers.

But yeah a console warning if the value provided isn't one of the handful of properties, or starts with cubic-bezier, is probably a really good idea :)