Repository: plotly/dash
File: components/dash-core-components/src/fragments/Graph.react.js (JavaScript)

Code before:
    plot(props) {
        let {figure, config} = props;
        const {animate, animation_options, responsive} = props;

        const gd = this.gd.current;
        figure = props._dashprivate_transformFigure(figure, gd);
        config = props._dashprivate_transformConfig(config, gd);

        if (
            animate &&
            this._hasPlotted &&
            figure.data.length === gd.data.length
        ) {
            // in case we've have figure frames,
            // we need to recreate frames before animation
            let result;
            if (figure.frames) {
                result = Plotly.deleteFrames(gd).then(() => {
                    return Plotly.addFrames(gd, figure.frames).then(() => {
                        return Plotly.animate(gd, figure, animation_options);
                    });
                });
            } else {
                result = Plotly.animate(gd, figure, animation_options);
            }
            return result;
        }

        const configClone = this.getConfig(config, responsive);
        const layoutClone = this.getLayout(figure.layout, responsive);

        gd.classList.add('dash-graph--pending');

        return Plotly.react(gd, {
            data: figure.data,
            layout: layoutClone,
            frames: figure.frames,
            config: configClone,
        }).then(() => {
            const gd = this.gd.current;

            // double-check gd hasn't been unmounted
            if (!gd) {
                return;
            }

            gd.classList.remove('dash-graph--pending');

            // in case we've made a new DOM element, transfer events
            if (this._hasPlotted && gd !== this._prevGd) {
                if (this._prevGd && this._prevGd.removeAllListeners) {

Review comment (refactor):
```suggestion
            if (figure.frames) {
                return Plotly.deleteFrames(gd)
                    .then(() => Plotly.addFrames(gd, figure.frames))
                    .then(() => Plotly.animate(gd, figure, animation_options));
            }
            return Plotly.animate(gd, figure, animation_options);
```
Nice find! Just simplifying the code a little...

I wonder though, it looks inconsistent that `layoutClone` happens after this. To cover the responsive case wouldn't we want the `Plotly.animate` calls to take `{data: figure.data, layout: layoutClone}` instead of `figure`?

Code after:

    plot(props) {
        let {figure, config} = props;
        const {animate, animation_options, responsive} = props;

        const gd = this.gd.current;
        figure = props._dashprivate_transformFigure(figure, gd);
        config = props._dashprivate_transformConfig(config, gd);

        const figureClone = {
            data: figure.data,
            layout: this.getLayout(figure.layout, responsive),
            frames: figure.frames,
            config: this.getConfig(config, responsive),
        };

        if (
            animate &&
            this._hasPlotted &&
            figure.data.length === gd.data.length
        ) {
            // in case we've have figure frames,
            // we need to recreate frames before animation
            if (figure.frames) {
                return Plotly.deleteFrames(gd)
                    .then(() => Plotly.addFrames(gd, figure.frames))
                    .then(() =>
                        Plotly.animate(gd, figureClone, animation_options)
                    );
            }
            return Plotly.animate(gd, figureClone, animation_options);
        }

        gd.classList.add('dash-graph--pending');

        return Plotly.react(gd, figureClone).then(() => {
            const gd = this.gd.current;

            // double-check gd hasn't been unmounted
            if (!gd) {
                return;
            }

            gd.classList.remove('dash-graph--pending');

            // in case we've made a new DOM element, transfer events
            if (this._hasPlotted && gd !== this._prevGd) {
                if (this._prevGd && this._prevGd.removeAllListeners) {
                    this._prevGd.removeAllListeners();
                    Plotly.purge(this._prevGd);
                }