最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ReactJS, CSS and SVG animations, and re-rendering - Stack Overflow

programmeradmin0浏览0评论

The issue can be seen in action here:

On first load, you'll see the blue circle going around and the red box fading out and in.
The circle is animated via svg tag and the box via css animations.
If you click anywhere on the canvas, the code triggers a re-render, which can be verified by opening the console.

My expectation would be for both animations to reset on click, however that does not happen.
I have a hunch that this has something to do with caching and react's shadow DOM.

Why's this happening? How to fix it?

The code is the following:

#nonSvgBox {
  animation-duration: 1s;
  animation-name: fade;
  width: 100px;
  height: 100px;
  background-color: red;
}

@keyframes fade {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
class Component extends React.Component {
  onClick() {
    this.setState({a: 1});
  }

  render() {
    console.log('rendering');
    return (
      <div onClick={() => this.onClick()}>
        <svg>
          <path 
            stroke="blue"
            strokeWidth="10"
            fill="transparent"
            d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"
            strokeDasharray="251.2,251.2">
            <animate
              attributeType="css"
              attributeName="stroke-dasharray"
              from="0" to="251.2" dur="1s" />
          </path>
        </svg>
        <div id="nonSvgBox"></div>
      </div>
    );
  }
}

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

Thank you.

The issue can be seen in action here:
https://codepen.io/fsabe/pen/opEVNR?editors=0110

On first load, you'll see the blue circle going around and the red box fading out and in.
The circle is animated via svg tag and the box via css animations.
If you click anywhere on the canvas, the code triggers a re-render, which can be verified by opening the console.

My expectation would be for both animations to reset on click, however that does not happen.
I have a hunch that this has something to do with caching and react's shadow DOM.

Why's this happening? How to fix it?

The code is the following:

#nonSvgBox {
  animation-duration: 1s;
  animation-name: fade;
  width: 100px;
  height: 100px;
  background-color: red;
}

@keyframes fade {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
class Component extends React.Component {
  onClick() {
    this.setState({a: 1});
  }

  render() {
    console.log('rendering');
    return (
      <div onClick={() => this.onClick()}>
        <svg>
          <path 
            stroke="blue"
            strokeWidth="10"
            fill="transparent"
            d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"
            strokeDasharray="251.2,251.2">
            <animate
              attributeType="css"
              attributeName="stroke-dasharray"
              from="0" to="251.2" dur="1s" />
          </path>
        </svg>
        <div id="nonSvgBox"></div>
      </div>
    );
  }
}

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

Thank you.

Share Improve this question edited Jan 10, 2018 at 1:51 fs_ asked Jan 10, 2018 at 1:39 fs_fs_ 1962 silver badges7 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

React is reusing the elements, therefore the animations won't replay b/c they've already played for the current elements.

I think it's easier to resort to dom operations in this situation, versus some setState trickery.

https://codepen.io/guanzo/pen/vpdPzX?editors=0110

Store the refs to the 2 elements, then trigger the animations with JS.

class Component extends React.Component {
  onClick() {
    this.svgAnimate.beginElement()//triggers animation
    this.square.style.animation = 'none';//override css animation
    this.square.offsetHeight; /* trigger reflow */
    this.square.style.animation = null; //fallback to css animation
  }

    render() {
    console.log('rendering');
        return (
            <div onClick={() => this.onClick()}>
                <svg>
                    <path 
                        stroke="blue"
            strokeWidth="10"
                        fill="transparent"
                        d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"
            strokeDasharray="251.2,251.2">
              <animate
                ref={(svgAnimate) => { this.svgAnimate = svgAnimate; }} 
                attributeType="css"
                attributeName="stroke-dasharray"
                from="0" to="251.2" dur="1s" />
                </path>
              </svg>
        <div id="nonSvgBox"
          ref={(square) => { this.square = square; }} 
          ></div>
            </div>
        );
    }
}

ReactDOM.render(<Component />, document.getElementById('app'));
发布评论

评论列表(0)

  1. 暂无评论