Bostjan Bostjan - 4 months ago 84
React JSX Question

Animate table rows with react

I have a table rendered with react (about 100 rows), but I would like the effect of the rows appearing one by one. Is there a way to do this with React? Below is my React code (the derivePairs funtion on the willMount procedure comes up with the data for the table).

var columns = [
{ key: 'pairNo', label: 'Zaporedna številka' },
{ key: 'homeTeam', label: 'Domača ekipa' },
{ key: 'awayTeam', label: 'Gostujoča ekipa' },
{ key: 'score', label: 'Rezultat' }
];

var Table = React.createClass({

getInitialState: function() {
return {data: this.props.data};
},

componentWillMount: function() {
derivePairs();
},

render: function() {
var headerComponents = this.generateHeaders(),
rowComponents = this.generateRows();

return (
<table>
<thead>{headerComponents}</thead>
<tbody>{rowComponents}</tbody>
</table>
);
},

generateHeaders: function() {
var cols = this.props.cols; // [{key, label}]

// generate our header (th) cell components
return cols.map(function(colData) {
return <th key={colData.key}>{colData.label}</th>;
});
},

generateRows: function() {
var cols = this.props.cols, // [{key, label}]
data = this.props.data;

var round=1;
var pairNo=1;
var oldRound=0;
var teamName=null;
return this.state.data.map(function(item, i) {
// handle the column data within each row
var htmlExcerpt = null;
var len = Object.keys(cols).length;
if (oldRound !== item.round) {
i=i+1;
htmlExcerpt = <tr key={'round'+item.round}><td colSpan={len}>Round: {item.round}</td></tr>;
oldRound = item.round;
}
var cells = cols.map(function(colData) {
console.log(colData);
// colData.key might be "firstName"
if (colData.key == "pairNo") {
return (<td> {pairNo} </td>);
} else {
if (colData.key == "homeTeam" || colData.key == "awayTeam") {
teamName = config.teams[item[colData.key]].name;
return (<td> {teamName} </td>);
} else {
return (<td> {item[colData.key]} </td>);
}
}
});
if (htmlExcerpt !== null) {
return [htmlExcerpt,<tr className=enter-data key={i}> {cells} </tr>];
} else {
return <tr className=enter-data key={i}> {cells} </tr>;
}
pairNo=pairNo+1;
});
}
});

ReactDOM.render(<Table cols={columns} data={config.pairs}/>, document.getElementById('roundPairs'));


Thanks for the help.

Answer

You can achieve this by using ReactCSSTransitionGroup package.

Your render method should be like this:

// ...

render: function() {
    var headerComponents = this.generateHeaders(),
        rowComponents = this.generateRows();

    return (
        <table>
            <thead>{headerComponents}</thead>
            <ReactCSSTransitionGroup
              transitionName="fade"
              transitionEnterTimeout={500}
              transitionLeaveTimeout={300}
              transitionAppearTimeout={500}
              transitionAppear={true}
              component="tbody"
            >
              {rowComponents}
            </ReactCSSTransitionGroup>
        </table>
    );
},

// ...

Next, you should define css classes. For fade animation name, they should be:

.fade-enter {
  opacity: 0.01;
}

.fade-enter.fade-enter-active {
  opacity: 1;
  transition: opacity 500ms ease-in;
}

.fade-leave {
  opacity: 1;
}

.fade-leave.fade-leave-active {
  opacity: 0.01;
  transition: opacity 300ms ease-in;
}

.fade-appear {
  opacity: 0.01;
}

.fade-appear.fade-appear-active {
  opacity: 1;
  transition: opacity .5s ease-in;
}