react-art icon indicating copy to clipboard operation
react-art copied to clipboard

50x performance hit vs <canvas>

Open nornagon opened this issue 10 years ago • 4 comments

Perhaps I'm doing something trivially wrong, but with the below code which draws 2000 random rectangles on the canvas, react-art runs at about 5fps on my machine. The comparable code that uses the canvas API directly runs at a smooth 60fps. In fact, it takes until about 100,000 rects to bring the implementation down to 5fps.

Most (~70%) of the time seems to be spent in the ReactMultiChild.Mixin._updateChildren method:

Most of the self-time that isn't GC is in ReactElement: developer_tools_-_http___localhost_5000_transcriptic_p17rvy7j9dzrw_runs_r17rvydszmnab_admin

Here's the code:

Test = React.createClass
  render: ->
    React.createElement 'div',
      onMouseMove: => @forceUpdate()
      onMouseDown: => @ivl = setInterval (=> @forceUpdate()), 16
      onMouseUp: => clearInterval @ivl
      React.createElement Surface,
        width: 800, height: 800
        React.createElement Group,
          y: 10, x: 10
          for [1..2000]
            React.createElement Rectangle, x: Math.random() * 800, y: Math.random() * 800, width: Math.random() * 40, height: Math.random() * 40, fill: 'red'



TestCanvas = React.createClass
  render: ->
    React.createElement 'canvas',
      width: 800 * devicePixelRatio, height: 800 * devicePixelRatio
      style: {
        width: 800
        height: 800
      }
      onMouseMove: => @paint()
      onMouseDown: => @ivl = setInterval @paint, 16
      onMouseUp: => clearInterval @ivl
  componentDidMount: ->
    @paint()

  paint: ->
    ctx = @getDOMNode().getContext '2d'
    ctx.save()
    ctx.scale(devicePixelRatio, devicePixelRatio)
    ctx.clearRect(0, 0, 800, 800)
    ctx.fillStyle = 'red'
    for [1..2000]
      ctx.fillRect Math.random() * 800, Math.random() * 800, Math.random() * 40, Math.random() * 40
    ctx.restore()

nornagon avatar Jul 06 '15 16:07 nornagon

What are you using to measure your canvas frame rate?

demc avatar Jul 08 '15 19:07 demc

Chrome devtools fps meter. On Wed, Jul 8, 2015 at 12:14 dmcmillen [email protected] wrote:

What are you using to measure your canvas frame rate?

— Reply to this email directly or view it on GitHub https://github.com/reactjs/react-art/issues/52#issuecomment-119700163.

nornagon avatar Jul 08 '15 19:07 nornagon

At the very least, you should be using the production (minified, NODE_ENV=production) version of React.

sophiebits avatar Jul 15 '15 14:07 sophiebits

I'm not sure if this would completely solve your problem, but I see some things that don't look right to me. That ReactMultiChild.Mixin._updateChildren is called from ReactEventListener.dispatchEvent, that's probably because of onMouseMove: => @paint() and onMouseMove: => @forceUpdate(). Mouse move events are firing at a very high rate, what you want to do is save the last event object to a variable, and then only render component with those last mouse move values once per frame. Now I know that react is not using request animation frame by default, you may want to look into https://github.com/petehunt/react-raf-batching.

pavlelekic avatar Oct 10 '15 06:10 pavlelekic